# Java Web开发核心:JSON处理、测试与会话管理实战
Java Web开发涉及多个核心技术点,包括JSON数据交互、单元测试编写以及会话管理机制。本文将深入探讨这些关键技术的实践应用,为构建稳健的Web应用提供完整解决方案。
## JSON数据处理
### Jackson库基础配置
```xml
<!-- Maven依赖配置 -->
<dependencies>
<!-- Jackson核心 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
<!-- Jackson日期时间支持 -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.15.2</version>
</dependency>
</dependencies>
```
### JSON序列化与反序列化
```java
// 用户实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Long id;
private String username;
private String email;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@JsonIgnore // 忽略密码字段的序列化
private String password;
// 自定义序列化逻辑
@JsonGetter("displayName")
public String getDisplayName() {
return username + " (" + email + ")";
<"gjst.nbazhib.com">
<"gpto.nbazhib.com">
<"zfzw.nbazhib.com">
}
}
// JSON工具类
@Component
public class JsonUtils {
private static final ObjectMapper objectMapper;
static {
objectMapper = new ObjectMapper();
// 配置ObjectMapper
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.registerModule(new JavaTimeModule());
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
public static String toJson(Object obj) {
try {
return objectMapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new RuntimeException("JSON序列化失败", e);
}
}
public static <T> T fromJson(String json, Class<T> clazz) {
try {
return objectMapper.readValue(json, clazz);
} catch (JsonProcessingException e) {
throw new RuntimeException("JSON反序列化失败", e);
}
}
public static <T> T fromJson(String json, TypeReference<T> typeReference) {
try {
return objectMapper.readValue(json, typeReference);
} catch (JsonProcessingException e) {
throw new RuntimeException("JSON反序列化失败", e);
}
}
}
// 使用示例
public class JsonExample {
<"vvqj.nbazhib.com">
<"jabg.nbazhib.com">
<"lums.nbazhib.com">
public static void main(String[] args) {
User user = new User(1L, "john_doe", "john@example.com",
LocalDateTime.now(), "encrypted_password");
// 序列化为JSON字符串
String json = JsonUtils.toJson(user);
System.out.println("序列化结果: " + json);
// 输出: {"id":1,"username":"john_doe","email":"john@example.com",
// "createTime":"2023-10-25 14:30:00","displayName":"john_doe (john@example.com)"}
// 反序列化
User deserializedUser = JsonUtils.fromJson(json, User.class);
System.out.println("反序列化用户名: " + deserializedUser.getUsername());
}
}
```
### Spring MVC中的JSON处理
```java
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
// 返回JSON响应
@GetMapping("/{id}")
public ResponseEntity<ApiResponse<User>> getUserById(@PathVariable Long id) {
try {
User user = userService.getUserById(id);
return ResponseEntity.ok(ApiResponse.success(user));
} catch (UserNotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(ApiResponse.error("用户不存在"));
}
}
// 接收JSON请求体
@PostMapping
public ResponseEntity<ApiResponse<User>> createUser(@Valid @RequestBody UserCreateRequest request) {
User user = userService.createUser(request);
return ResponseEntity.status(HttpStatus.CREATED)
.body(ApiResponse.success(user));
}
// 返回列表数据
@GetMapping
public ResponseEntity<ApiResponse<List<User>>> listUsers(
<"dcge.nbazhib.com">
<"yuhz.nbazhib.com">
<"antc.nbazhib.com">
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
Page<User> users = userService.listUsers(page, size);
Map<String, Object> data = new HashMap<>();
data.put("list", users.getContent());
data.put("total", users.getTotalElements());
data.put("pages", users.getTotalPages());
return ResponseEntity.ok(ApiResponse.success(data));
}
}
// 统一API响应格式
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ApiResponse<T> {
private boolean success;
private String message;
private T data;
private long timestamp;
public static <T> ApiResponse<T> success(T data) {
return new ApiResponse<>(true, "操作成功", data, System.currentTimeMillis());
}
public static <T> ApiResponse<T> error(String message) {
return new ApiResponse<>(false, message, null, System.currentTimeMillis());
}
public static <T> ApiResponse<T> success(String message, T data) {
return new ApiResponse<>(true, message, data, System.currentTimeMillis());
}
}
```
## 单元测试实践
### 测试环境配置
```xml
<!-- 测试依赖 -->
<dependency>
<"crsf.nbazhib.com">
<"pgfz.nbazhib.com">
<"nzew.nbazhib.com">
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
```
### Service层测试
```java
// 用户服务测试
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void testGetUserById_Success() {
// 准备测试数据
Long userId = 1L;
User mockUser = new User(userId, "testuser", "test@example.com",
LocalDateTime.now(), "password");
// 设置Mock行为
when(userRepository.findById(userId)).thenReturn(Optional.of(mockUser));
// 执行测试
User result = userService.getUserById(userId);
// 验证结果
assertNotNull(result);
assertEquals(userId, result.getId());
assertEquals("testuser", result.getUsername());
// 验证Mock交互
verify(userRepository, times(1)).findById(userId);
}
@Test
void testGetUserById_NotFound() {
// 设置Mock行为
Long userId = 999L;
when(userRepository.findById(userId)).thenReturn(Optional.empty());
// 执行测试并验证异常
UserNotFoundException exception = assertThrows(
UserNotFoundException.class,
() -> userService.getUserById(userId)
);
assertEquals("用户不存在: " + userId, exception.getMessage());
verify(userRepository, times(1)).findById(userId);
}
@Test
void testCreateUser_ValidInput() {
// 准备测试数据
UserCreateRequest request = new UserCreateRequest("newuser",
"new@example.com", "password123");
User savedUser = new User(1L, "newuser", "new@example.com",
LocalDateTime.now(), "encrypted_password");
// 设置Mock行为
when(userRepository.existsByUsername("newuser")).thenReturn(false);
when(userRepository.existsByEmail("new@example.com")).thenReturn(false);
when(userRepository.save(any(User.class))).thenReturn(savedUser);
// 执行测试
User result = userService.createUser(request);
// 验证结果
assertNotNull(result);
assertEquals("newuser", result.getUsername());
assertEquals("new@example.com", result.getEmail());
// 验证Mock交互
verify(userRepository, times(1)).existsByUsername("newuser");
verify(userRepository, times(1)).existsByEmail("new@example.com");
verify(userRepository, times(1)).save(any(User.class));
}
@ParameterizedTest
@MethodSource("invalidUserProvider")
void testCreateUser_InvalidInput(String username, String email, String expectedError) {
UserCreateRequest request = new UserCreateRequest(username, email, "password");
BusinessException exception = assertThrows(
BusinessException.class,
() -> userService.createUser(request)
);
assertTrue(exception.getMessage().contains(expectedError));
}
private static Stream<Arguments> invalidUserProvider() {
return Stream.of(
Arguments.of("", "valid@example.com", "用户名不能为空"),
Arguments.of("user", "invalid-email", "邮箱格式不正确"),
Arguments.of("ab", "valid@example.com", "用户名长度必须在3-20个字符之间")
);
}
}
```
### Controller层测试
```java
@WebMvcTest(UserController.class)
class UserControllerTest {
<"kaos.nbazhib.com">
<"jtnt.nbazhib.com">
<"rxxe.nbazhib.com">
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Autowired
private ObjectMapper objectMapper;
@Test
void testGetUser_Success() throws Exception {
// 准备测试数据
Long userId = 1L;
User mockUser = new User(userId, "testuser", "test@example.com",
LocalDateTime.now(), "password");
// 设置Mock行为
when(userService.getUserById(userId)).thenReturn(mockUser);
// 执行请求并验证
mockMvc.perform(get("/api/users/{id}", userId)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.data.id").value(userId))
.andExpect(jsonPath("$.data.username").value("testuser"))
.andExpect(jsonPath("$.data.email").value("test@example.com"));
}
@Test
void testCreateUser_ValidInput() throws Exception {
// 准备测试数据
UserCreateRequest request = new UserCreateRequest("newuser",
"new@example.com", "password123");
User createdUser = new User(1L, "newuser", "new@example.com",
LocalDateTime.now(), "encrypted_password");
// 设置Mock行为
when(userService.createUser(any(UserCreateRequest.class))).thenReturn(createdUser);
// 执行请求并验证
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.data.username").value("newuser"));
}
@Test
void testCreateUser_InvalidInput() throws Exception {
// 准备无效的测试数据
UserCreateRequest request = new UserCreateRequest("", "invalid-email", "123");
// 执行请求并验证
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.success").value(false));
}
@Test
void testListUsers() throws Exception {
// 准备测试数据
List<User> users = Arrays.asList(
new User(1L, "user1", "user1@example.com", LocalDateTime.now(), "pwd1"),
new User(2L, "user2", "user2@example.com", LocalDateTime.now(), "pwd2")
);
Page<User> userPage = new PageImpl<>(users, PageRequest.of(0, 10), 2);
// 设置Mock行为
when(userService.listUsers(0, 10)).thenReturn(userPage);
// 执行请求并验证
mockMvc.perform(get("/api/users")
.param("page", "0")
.param("size", "10")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.data.list.length()").value(2))
.andExpect(jsonPath("$.data.total").value(2))
.andExpect(jsonPath("$.data.pages").value(1));
}
}
```
## Cookie与Session管理
### Cookie操作
```java
@RestController
@RequestMapping("/auth")
<"myrm.nbazhib.com">
<"gzgf.nbazhib.com">
<"qspl.nbazhib.com">
public class AuthController {
@PostMapping("/login")
public ResponseEntity<ApiResponse<String>> login(
@RequestBody LoginRequest request,
HttpServletResponse response) {
// 验证用户凭据
User user = userService.authenticate(request.getUsername(), request.getPassword());
// 生成Token
String token = JwtUtils.generateToken(user);
// 设置HttpOnly Cookie
Cookie tokenCookie = new Cookie("auth_token", token);
tokenCookie.setHttpOnly(true);
tokenCookie.setSecure(true); // HTTPS环境下启用
tokenCookie.setPath("/");
tokenCookie.setMaxAge(7 * 24 * 60 * 60); // 7天有效期
response.addCookie(tokenCookie);
// 设置用户信息Cookie(非敏感信息)
Cookie userCookie = new Cookie("user_info",
URLEncoder.encode(user.getUsername(), StandardCharsets.UTF_8));
userCookie.setPath("/");
userCookie.setMaxAge(7 * 24 * 60 * 60);
response.addCookie(userCookie);
return ResponseEntity.ok(ApiResponse.success("登录成功"));
}
@PostMapping("/logout")
public ResponseEntity<ApiResponse<String>> logout(HttpServletResponse response) {
// 清除认证Cookie
Cookie tokenCookie = new Cookie("auth_token", "");
tokenCookie.setHttpOnly(true);
tokenCookie.setSecure(true);
tokenCookie.setPath("/");
tokenCookie.setMaxAge(0); // 立即过期
response.addCookie(tokenCookie);
// 清除用户信息Cookie
Cookie userCookie = new Cookie("user_info", "");
userCookie.setPath("/");
userCookie.setMaxAge(0);
response.addCookie(userCookie);
return ResponseEntity.ok(ApiResponse.success("退出成功"));
}
@GetMapping("/profile")
public ResponseEntity<ApiResponse<User>> getProfile(
@CookieValue(value = "auth_token", defaultValue = "") String token) {
if (token.isEmpty()) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body(ApiResponse.error("未认证"));
}
try {
User user = JwtUtils.validateToken(token);
return ResponseEntity.ok(ApiResponse.success(user));
} catch (JwtException e) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body(ApiResponse.error("Token无效"));
}
}
}
```
### Session管理
```java
@RestController
@RequestMapping("/session")
@SessionAttributes("cart") // 声明session属性
public class SessionController {
<"uzwa.nbazhib.com">
<"dihn.nbazhib.com">
<"teok.nbazhib.com">
// 购物车操作
@PostMapping("/cart/add")
public ResponseEntity<ApiResponse<String>> addToCart(
@RequestParam Long productId,
@RequestParam Integer quantity,
@ModelAttribute("cart") ShoppingCart cart) {
cart.addItem(productId, quantity);
return ResponseEntity.ok(ApiResponse.success("商品已添加到购物车"));
}
@GetMapping("/cart")
public ResponseEntity<ApiResponse<ShoppingCart>> getCart(
@ModelAttribute("cart") ShoppingCart cart) {
return ResponseEntity.ok(ApiResponse.success(cart));
}
@PostMapping("/cart/clear")
public ResponseEntity<ApiResponse<String>> clearCart(
SessionStatus sessionStatus) {
sessionStatus.setComplete(); // 清除session
return ResponseEntity.ok(ApiResponse.success("购物车已清空"));
}
// 初始化购物车
@ModelAttribute("cart")
public ShoppingCart initializeCart() {
return new ShoppingCart();
}
// 用户会话管理
@PostMapping("/login")
public ResponseEntity<ApiResponse<String>> sessionLogin(
@RequestBody LoginRequest request,
HttpSession session) {
User user = userService.authenticate(request.getUsername(), request.getPassword());
// 将用户信息存入session
session.setAttribute("currentUser", user);
session.setAttribute("loginTime", LocalDateTime.now());
session.setMaxInactiveInterval(30 * 60); // 30分钟超时
// 记录会话信息
session.setAttribute("userAgent", request.getUserAgent());
session.setAttribute("ipAddress", request.getIpAddress());
return ResponseEntity.ok(ApiResponse.success("登录成功"));
}
@GetMapping("/userinfo")
public ResponseEntity<ApiResponse<Map<String, Object>>> getUserInfo(HttpSession session) {
User currentUser = (User) session.getAttribute("currentUser");
if (currentUser == null) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body(ApiResponse.error("用户未登录"));
}
Map<String, Object> userInfo = new HashMap<>();
userInfo.put("user", currentUser);
userInfo.put("loginTime", session.getAttribute("loginTime"));
userInfo.put("sessionId", session.getId());
userInfo.put("lastAccessedTime", new Date(session.getLastAccessedTime()));
return ResponseEntity.ok(ApiResponse.success(userInfo));
}
@PostMapping("/logout")
public ResponseEntity<ApiResponse<String>> sessionLogout(HttpSession session) {
// 记录登出日志
User user = (User) session.getAttribute("currentUser");
if (user != null) {
log.info("用户 {} 登出,会话ID: {}", user.getUsername(), session.getId());
}
// 使session失效
session.invalidate();
return ResponseEntity.ok(ApiResponse.success("退出成功"));
}
}
// 购物车类
@Data
public class ShoppingCart implements Serializable {
private Map<Long, CartItem> items = new HashMap<>();
private LocalDateTime createTime = LocalDateTime.now();
public void addItem(Long productId, Integer quantity) {
CartItem item = items.getOrDefault(productId, new CartItem(productId, 0));
item.setQuantity(item.getQuantity() + quantity);
items.put(productId, item);
}
public void removeItem(Long productId) {
items.remove(productId);
}
public void updateQuantity(Long productId, Integer quantity) {
if (items.containsKey(productId)) {
if (quantity <= 0) {
removeItem(productId);
} else {
items.get(productId).setQuantity(quantity);
}
}
}
public BigDecimal getTotalPrice() {
return items.values().stream()
.map(CartItem::getTotalPrice)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
public int getTotalItems() {
return items.values().stream()
.mapToInt(CartItem::getQuantity)
.sum();
}
public void clear() {
items.clear();
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class CartItem implements Serializable {
<"xwku.nbazhib.com">
<"xlkq.nbazhib.com">
<"gpdk.nbazhib.com">
private Long productId;
private Integer quantity;
private String productName;
private BigDecimal unitPrice;
public CartItem(Long productId, Integer quantity) {
this.productId = productId;
this.quantity = quantity;
}
public BigDecimal getTotalPrice() {
if (unitPrice == null) return BigDecimal.ZERO;
return unitPrice.multiply(BigDecimal.valueOf(quantity));
}
}
```
## 请求处理与数据验证
### 请求参数处理
```java
@RestController
@RequestMapping("/api")
public class RequestController {
// 路径参数
@GetMapping("/users/{id}/orders/{orderId}")
public ResponseEntity<ApiResponse<Order>> getOrder(
@PathVariable Long id,
@PathVariable Long orderId,
@PathVariable Map<String, String> pathVars) {
log.info("路径参数: {}", pathVars);
Order order = orderService.getOrder(id, orderId);
return ResponseEntity.ok(ApiResponse.success(order));
}
// 查询参数
@GetMapping("/products")
public ResponseEntity<ApiResponse<List<Product>>> searchProducts(
@RequestParam String keyword,
@RequestParam(required = false) String category,
@RequestParam(defaultValue = "0") Double minPrice,
@RequestParam(defaultValue = "10000") Double maxPrice,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size) {
ProductSearchCriteria criteria = new ProductSearchCriteria(keyword, category,
minPrice, maxPrice);
Page<Product> products = productService.searchProducts(criteria, page, size);
return ResponseEntity.ok(ApiResponse.success(products.getContent()));
}
// 请求头处理
@GetMapping("/version")
public ResponseEntity<ApiResponse<String>> getVersion(
@RequestHeader("User-Agent") String userAgent,
@RequestHeader(value = "X-API-Version", defaultValue = "v1") String apiVersion) {
log.info("User-Agent: {}, API Version: {}", userAgent, apiVersion);
String versionInfo = String.format("API Version: %s, Client: %s",
apiVersion, userAgent);
return ResponseEntity.ok(ApiResponse.success(versionInfo));
}
// 自定义请求头
@PostMapping("/upload")
public ResponseEntity<ApiResponse<String>> uploadFile(
@RequestHeader("X-File-Size") long fileSize,
@RequestHeader("X-File-Type") String fileType,
@RequestBody byte[] fileData) {
if (fileSize > 10 * 1024 * 1024) { // 10MB限制
return ResponseEntity.badRequest()
.body(ApiResponse.error("文件大小超过限制"));
}
String fileId = fileService.saveFile(fileData, fileType);
return ResponseEntity.ok(ApiResponse.success(fileId));
}
}
// 数据验证
@Data
public class UserCreateRequest {
@NotBlank(message = "用户名不能为空")
@Size(min = 3, max = 20, message = "用户名长度必须在3-20个字符之间")
private String username;
@NotBlank(message = "邮箱不能为空")
@Email(message = "邮箱格式不正确")
private String email;
@NotBlank(message = "密码不能为空")
@Size(min = 6, message = "密码长度至少6位")
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$",
message = "密码必须包含大小写字母和数字")
private String password;
@AssertTrue(message = "必须接受用户协议")
private Boolean agreedToTerms;
}
// 全局异常处理
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiResponse<Map<String, String>>> handleValidationExceptions(
MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage()));
return ResponseEntity.badRequest()
.body(ApiResponse.error("参数验证失败", errors));
}
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<ApiResponse<Map<String, String>>> handleConstraintViolation(
ConstraintViolationException ex) {
Map<String, String> errors = new HashMap<>();
ex.getConstraintViolations().forEach(violation -> {
String fieldName = violation.getPropertyPath().toString();
String message = violation.getMessage();
errors.put(fieldName, message);
});
return ResponseEntity.badRequest()
.body(ApiResponse.error("参数验证失败", errors));
}
@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<ApiResponse<String>> handleJsonParseException(
HttpMessageNotReadableException ex) {
return ResponseEntity.badRequest()
.body(ApiResponse.error("JSON格式不正确"));
}
}
```
## 总结
本文详细探讨了Java Web开发中的三个核心技术领域:
1. **JSON数据处理**:使用Jackson库进行高效的序列化和反序列化,统一API响应格式
2. **单元测试**:通过JUnit 5和Mockito编写可靠的单元测试,确保代码质量
3. **会话管理**:合理使用Cookie和Session管理用户状态,保证应用安全性
这些技术点的熟练掌握对于构建健壮、可维护的Java Web应用至关重要。通过合理的架构设计和规范的编码实践,可以显著提升应用的质量和开发效率。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3102430/ ,如需转载,请注明出处,否则将追究法律责任。