如何写出优雅的Controller层代码(controller代码怎么写)

  本篇文章为你整理了如何写出优雅的Controller层代码(controller代码怎么写)的详细内容,包含有controller层怎么写 controller代码怎么写 controller 层 controller层的作用 如何写出优雅的Controller层代码,希望能帮助你了解 如何写出优雅的Controller层代码。

  请求方式(一般就是 get、set,当然还有 put、delete)

  请求数据(request,有 head 跟 body)

  响应数据(response)

  Controller 主要的工作有以下几项:

  接收请求并解析参数

  调用 Service 执行具体的业务代码(可能包含参数校验)

  捕获业务逻辑异常做出反馈

  业务逻辑执行成功做出响应

  解决以下 3 个问题:

  返回响应数据该如何统一的进行处理

  接收到请求,处理业务逻辑时抛出了异常又该如何处理

  当接收到请求时,如何优雅的校验参数

  统一返回结构

  封装Result

  

package com.wanqi.result;

 

  public interface IResult {

   Integer getCode();

   String getMessage();

  

 

  定义状态码

  

package com.wanqi.result;

 

  public enum ResultEnum implements IResult {

   SUCCESS(2001, "接口调用成功"),

   VALIDATE_FAILED(2002, "参数校验失败"),

   COMMON_FAILED(2003, "接口调用失败"),

   FORBIDDEN(2004, "没有权限访问资源"),

   DATA_CONVERSION(2005, "数据转换异常");

   private Integer code;

   private String message;

   ResultEnum(int code, String message) {

   this.code=code;

   this.message=message;

   @Override

   public Integer getCode() {

   return code;

   @Override

   public String getMessage() {

   return message;

  

 

  Result包装类

  

package com.wanqi.result;

 

  public class Result T {

   private Integer code;

   private String message;

   private T data;

   public Integer getCode() {

   return code;

   public void setCode(Integer code) {

   this.code = code;

   public String getMessage() {

   return message;

   public void setMessage(String message) {

   this.message = message;

   public T getData() {

   return data;

   public void setData(T data) {

   this.data = data;

   public Result() {

   public Result(Integer code, String message, T data) {

   this.code = code;

   this.message = message;

   this.data = data;

   public static T Result T success(T data) {

   return new Result (ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMessage(), data);

   public static T Result T success(String message, T data) {

   return new Result (ResultEnum.SUCCESS.getCode(), message, data);

   public static Result ? failed() {

   return new Result (ResultEnum.COMMON_FAILED.getCode(), ResultEnum.COMMON_FAILED.getMessage(), null);

   public static Result ? failed(String message) {

   return new Result (ResultEnum.COMMON_FAILED.getCode(), message, null);

   public static Result ? failed(Integer code,String message) {

   return new Result (code, message, null);

   public static Result ? failed(IResult errorResult) {

   return new Result (errorResult.getCode(), errorResult.getMessage(), null);

   public static T Result T instance(Integer code, String message, T data) {

   Result T result = new Result ();

   result.setCode(code);

   result.setMessage(message);

   result.setData(data);

   return result;

  

 

  统一包装处理

  

package com.wanqi.advice;

 

  import com.fasterxml.jackson.core.JsonProcessingException;

  import com.fasterxml.jackson.databind.ObjectMapper;

  import com.wanqi.exception.APIException;

  import com.wanqi.result.Result;

  import org.springframework.core.MethodParameter;

  import org.springframework.http.MediaType;

  import org.springframework.http.converter.HttpMessageConverter;

  import org.springframework.http.server.ServerHttpRequest;

  import org.springframework.http.server.ServerHttpResponse;

  import org.springframework.web.bind.annotation.RestControllerAdvice;

  import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

  // 如果引入了swagger或knife4j的文档生成组件,这里需要仅扫描自己项目的包,否则文档无法正常生成

  @RestControllerAdvice(basePackages = "com.wanqi.controller")

  public class ResponseAdvice implements ResponseBodyAdvice Object {

   @Override

   public boolean supports(MethodParameter returnType, Class ? extends HttpMessageConverter ? converterType) {

   // response是Result类型不进行包装

   return !returnType.getParameterType().isAssignableFrom(Result.class);

  
@Override

   public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class ? extends HttpMessageConverter ? selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {

   if(returnType.getGenericParameterType().equals(String.class)){

   ObjectMapper objectMapper = new ObjectMapper();

   try {

   return objectMapper.writeValueAsString(Result.success(body));

   } catch (JsonProcessingException e) {

   throw new APIException(e.getMessage());

   return Result.success(body);

  

 

  Controller层

  

package com.wanqi.controller;

 

  import com.wanqi.pojo.TestDTO;

  import com.wanqi.pojo.UserDTO;

  import org.hibernate.validator.constraints.*;

  import org.springframework.validation.annotation.Validated;

  import org.springframework.web.bind.annotation.*;

  import javax.validation.constraints.Max;

  import javax.validation.constraints.Min;

  @RestController

  public class TestController {

   @PostMapping("/test")

   public TestDTO test(@RequestBody TestDTO testDTO) {

   return testDTO;

   @PostMapping("/test1")

   public String test1(@RequestBody TestDTO testDTO) {

   return testDTO.getName();

  

 

  不统一处理返回

  自定义注解

  

package com.wanqi.advice;

 

  import java.lang.annotation.ElementType;

  import java.lang.annotation.Retention;

  import java.lang.annotation.RetentionPolicy;

  import java.lang.annotation.Target;

  @Target({ElementType.METHOD})

  @Retention(RetentionPolicy.RUNTIME)

  public @interface NotControllerResponseAdvice {

  

 

  在增强过滤方法上过滤包含这个注解的方法

  

@RestControllerAdvice(basePackages = "com.wanqi.controller")

 

  public class ResponseAdvice implements ResponseBodyAdvice Object {

   @Override

   public boolean supports(MethodParameter returnType, Class ? extends HttpMessageConverter ? converterType) {

   // response是Result类型,或者注释了NotControllerResponseAdvice都不进行包装

   return !(returnType.getParameterType().isAssignableFrom(Result.class)

   returnType.hasMethodAnnotation(NotControllerResponseAdvice.class));

  .....

  

 

  controller

  在不需要统一处理的方法上使用@NotControllerResponseAdvice注解即可

  

package com.wanqi.controller;

 

  import com.wanqi.advice.NotControllerResponseAdvice;

  import com.wanqi.pojo.TestDTO;

  import com.wanqi.pojo.UserDTO;

  import com.wanqi.result.Result;

  import org.hibernate.validator.constraints.*;

  import org.springframework.validation.annotation.Validated;

  import org.springframework.web.bind.annotation.*;

  import javax.validation.Valid;

  import javax.validation.constraints.Max;

  import javax.validation.constraints.Min;

  @Validated

  @RestController

  public class TestController {

   @GetMapping("/health")

   @NotControllerResponseAdvice

   public String health() {

   return "success";

   @GetMapping("/health1")

   public Result health1() {

   return Result.success("dddd");

  

 

  自定义异常与统一拦截异常

  自定义异常

  

package com.wanqi.exception;

 

  import com.wanqi.result.ResultEnum;

  //自定义异常

  public class APIException extends RuntimeException {

   private int code;

   private String msg;

   public int getCode() {

   return code;

   public String getMsg() {

   return msg;

   public APIException(String message) {

   super(message);

   this.code = ResultEnum.DATA_CONVERSION.getCode();

   this.msg = ResultEnum.DATA_CONVERSION.getMessage();

  

 

  统一拦截异常

  

package com.wanqi.advice;

 

  import com.wanqi.exception.APIException;

  import com.wanqi.result.IResult;

  import com.wanqi.result.Result;

  import com.wanqi.result.ResultEnum;

  import org.springframework.util.StringUtils;

  import org.springframework.validation.BindingResult;

  import org.springframework.validation.FieldError;

  import org.springframework.web.bind.MethodArgumentNotValidException;

  import org.springframework.web.bind.annotation.ExceptionHandler;

  import org.springframework.web.bind.annotation.RestControllerAdvice;

  import javax.validation.ConstraintViolationException;

  //统一拦截异常

  @RestControllerAdvice(basePackages = "com.wanqi")

  public class ControllerExceptionAdvice {

   * 捕获 {@code APIException} 异常

   @ExceptionHandler({APIException.class})

   public Result ? handleBusinessException(APIException ex) {

   return Result.failed(ex.getMessage());

   * {@code @RequestBody} 参数校验不通过时抛出的异常处理

   @ExceptionHandler({MethodArgumentNotValidException.class})

   public Result ? handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {

   BindingResult bindingResult = ex.getBindingResult();

   StringBuilder sb = new StringBuilder("校验失败:");

   for (FieldError fieldError : bindingResult.getFieldErrors()) {

   sb.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(", ");

   String msg = sb.toString();

   if (StringUtils.hasText(msg)) {

   return Result.failed(new IResult() {

   @Override

   public Integer getCode() {

   return ResultEnum.VALIDATE_FAILED.getCode();

   @Override

   public String getMessage() {

   return msg;

   return Result.failed(ResultEnum.VALIDATE_FAILED);

   * {@code @PathVariable} 和 {@code @RequestParam} 参数校验不通过时抛出的异常处理

   @ExceptionHandler({ConstraintViolationException.class})

   public Result ? handleConstraintViolationException(ConstraintViolationException ex) {

   if (StringUtils.hasText(ex.getMessage())) {

   return Result.failed(ResultEnum.VALIDATE_FAILED.getCode(), ex.getMessage());

   return Result.failed(ResultEnum.VALIDATE_FAILED);

   * 顶级异常捕获并统一处理,当其他异常无法处理时候选择使用

   @ExceptionHandler({Exception.class})

   public Result ? handle(Exception ex) {

   return Result.failed(ex.getMessage());

  

 

  使用hibernate-validator,@Validated注解参数校验

  

 !-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -- 

 

   dependency

   groupId org.hibernate /groupId

   artifactId hibernate-validator /artifactId

   version 6.2.5.Final /version

   /dependency

  

 

  @RequestBody 参数校验

  Post、Put 请求的参数推荐使用 @RequestBody 请求体参数。

  对 @RequestBody 参数进行校验需要在对象中加入校验条件后,再搭配 @Validated 即可完成自动校验。

  UserDTO

  

package com.wanqi.pojo;

 

  
import org.hibernate.validator.constraints.*;

  import org.springframework.validation.annotation.Validated;

  import org.springframework.web.bind.annotation.*;

  import javax.validation.constraints.Max;

  import javax.validation.constraints.Min;

  @Validated

  @RestController

  public class TestController {

   // 使用@Valid或者@Validated

   @PostMapping("/user")

   public UserDTO user(@RequestBody @Validated UserDTO userDTO) {

   return userDTO;

  

 

  @PathVariable 和 @RequestParam 参数校验

  Get 请求的参数接收一般依赖这两个注解,但是处于 url 有长度限制和代码的可维护性,超过 5 个参数尽量用实体来传参。

  对 @PathVariable 和 @RequestParam 参数进行校验需要在入参声明约束的注解。

  controller

  

package com.wanqi.controller;

 

  import com.wanqi.pojo.TestDTO;

  import com.wanqi.pojo.UserDTO;

  import org.hibernate.validator.constraints.*;

  import org.springframework.validation.annotation.Validated;

  import org.springframework.web.bind.annotation.*;

  import javax.validation.Valid;

  import javax.validation.constraints.Max;

  import javax.validation.constraints.Min;

  @Validated

  @RestController

  public class TestController {

   @GetMapping("/{num}")

   public Integer detail(@PathVariable("num") @Min(value = 1 ,message = "不能小于1") @Max(20) Integer num) {

   return num * num;

   @GetMapping("/getByEmail")

   public String getByAccount(@RequestParam @NotBlank @Email String email) {

   return email;

  

 

  自定义校验规则

  自定义校验规则需要做两件事情:

  自定义注解类,定义错误信息和一些其他需要的内容

  注解校验器,定义判定规则

  自定义注解类

  

package com.wanqi.validator;

 

  import javax.validation.Constraint;

  import javax.validation.Payload;

  import java.lang.annotation.*;

  @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})

  @Retention(RetentionPolicy.RUNTIME)

  @Documented

  @Constraint(validatedBy = MobileValidator.class)

  public @interface Mobile {

   * 是否允许为空

   boolean required() default true;

   * 校验不通过返回的提示信息

   String message() default "不是一个手机号码格式";

   * Constraint要求的属性,用于分组校验和扩展,留空就好

   Class ? [] groups() default {};

   Class ? extends Payload [] payload() default {};

  

 

  注解校验器,实现ConstraintValidator接口

  

package com.wanqi.validator;

 

  import org.springframework.util.StringUtils;

  import javax.validation.ConstraintValidator;

  import javax.validation.ConstraintValidatorContext;

  import java.util.regex.Matcher;

  import java.util.regex.Pattern;

  public class MobileValidator implements ConstraintValidator Mobile, CharSequence {

   private boolean required = false;

   private final Pattern pattern = Pattern.compile("^1[34578][0-9]{9}$"); // 验证手机号

   * 在验证开始前调用注解里的方法,从而获取到一些注解里的参数

   * @param constraintAnnotation annotation instance for a given constraint declaration

   @Override

   public void initialize(Mobile constraintAnnotation) {

   this.required = constraintAnnotation.required();

   * 判断参数是否合法

   * @param value object to validate

   * @param context context in which the constraint is evaluated

   @Override

   public boolean isValid(CharSequence value, ConstraintValidatorContext context) {

   if (this.required) {

   // 验证

   return isMobile(value);

   if (StringUtils.hasText(value)) {

   // 验证

   return isMobile(value);

   return true;

   private boolean isMobile(final CharSequence str) {

   Matcher m = pattern.matcher(str);

   return m.matches();

  

 

  

package com.wanqi.controller;

 

  
import org.hibernate.validator.constraints.*;

  import org.springframework.validation.annotation.Validated;

  import org.springframework.web.bind.annotation.*;

  以上就是如何写出优雅的Controller层代码(controller代码怎么写)的详细内容,想要了解更多 如何写出优雅的Controller层代码的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: