Java Web 开发指南
目录
Web 框架
Spring MVC
java
@Controller
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping
public String listUsers(Model model) {
model.addAttribute("users", userService.findAll());
return "users/list";
}
@GetMapping("/{id}")
public String getUser(@PathVariable Long id, Model model) {
model.addAttribute("user", userService.findById(id));
return "users/detail";
}
@GetMapping("/new")
public String newUser(Model model) {
model.addAttribute("user", new User());
return "users/form";
}
@PostMapping
public String createUser(@ModelAttribute User user) {
userService.save(user);
return "redirect:/users";
}
}Thymeleaf 模板
html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>用户列表</title>
</head>
<body>
<h1>用户列表</h1>
<table>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>邮箱</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr th:each="user : ${users}">
<td th:text="${user.id}"></td>
<td th:text="${user.name}"></td>
<td th:text="${user.email}"></td>
<td>
<a th:href="@{/users/{id}(id=${user.id})}">查看</a>
<a th:href="@{/users/{id}/edit(id=${user.id})}">编辑</a>
</td>
</tr>
</tbody>
</table>
</body>
</html>静态文件
静态资源处理
java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/");
}
}会话管理
Spring Session
java
@Configuration
@EnableRedisHttpSession
public class SessionConfig {
@Bean
public LettuceConnectionFactory connectionFactory() {
return new LettuceConnectionFactory();
}
}
@Controller
public class UserController {
@PostMapping("/login")
public String login(@RequestParam String username,
@RequestParam String password,
HttpSession session) {
User user = userService.authenticate(username, password);
session.setAttribute("user", user);
return "redirect:/";
}
@GetMapping("/logout")
public String logout(HttpSession session) {
session.invalidate();
return "redirect:/login";
}
}表单处理
表单验证
java
@Controller
public class UserController {
@PostMapping("/register")
public String register(@Valid @ModelAttribute User user,
BindingResult result) {
if (result.hasErrors()) {
return "users/form";
}
userService.save(user);
return "redirect:/users";
}
}
public class User {
@NotBlank(message = "姓名不能为空")
private String name;
@Email(message = "邮箱格式不正确")
private String email;
@Size(min = 6, message = "密码长度不能小于6位")
private String password;
}文件上传
单文件上传
java
@Controller
public class FileController {
@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file) {
if (!file.isEmpty()) {
try {
String fileName = file.getOriginalFilename();
String filePath = "uploads/" + fileName;
File dest = new File(filePath);
file.transferTo(dest);
return "redirect:/success";
} catch (IOException e) {
return "redirect:/error";
}
}
return "redirect:/error";
}
}多文件上传
java
@Controller
public class FileController {
@PostMapping("/upload")
public String uploadFiles(@RequestParam("files") MultipartFile[] files) {
for (MultipartFile file : files) {
if (!file.isEmpty()) {
try {
String fileName = file.getOriginalFilename();
String filePath = "uploads/" + fileName;
File dest = new File(filePath);
file.transferTo(dest);
} catch (IOException e) {
return "redirect:/error";
}
}
}
return "redirect:/success";
}
}前端集成
集成 Vue.js
html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>用户管理</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<h1>用户列表</h1>
<table>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>邮箱</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="user in users">
<td>{{ user.id }}</td>
<td>{{ user.name }}</td>
<td>{{ user.email }}</td>
<td>
<button @click="editUser(user)">编辑</button>
<button @click="deleteUser(user.id)">删除</button>
</td>
</tr>
</tbody>
</table>
</div>
<script>
new Vue({
el: '#app',
data: {
users: []
},
mounted() {
this.loadUsers();
},
methods: {
loadUsers() {
axios.get('/api/users')
.then(response => {
this.users = response.data;
});
},
editUser(user) {
// 处理编辑
},
deleteUser(id) {
axios.delete(`/api/users/${id}`)
.then(() => {
this.loadUsers();
});
}
}
});
</script>
</body>
</html>性能优化
缓存控制
java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CacheControlInterceptor())
.addPathPatterns("/static/**");
}
}
public class CacheControlInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
response.setHeader("Cache-Control", "public, max-age=31536000");
return true;
}
}压缩
java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorParameter(true)
.parameterName("mediaType")
.ignoreAcceptHeader(false)
.defaultContentType(MediaType.APPLICATION_JSON)
.mediaType("json", MediaType.APPLICATION_JSON)
.mediaType("xml", MediaType.APPLICATION_XML);
}
}安全实践
CSRF 保护
java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.authorizeRequests()
.antMatchers("/public/**").permitAll()
.anyRequest().authenticated();
}
}XSS 防护
java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new XssInterceptor())
.addPathPatterns("/**");
}
}
public class XssInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
response.setHeader("X-XSS-Protection", "1; mode=block");
response.setHeader("Content-Security-Policy", "default-src 'self'");
return true;
}
}