public static
CodeMsg codeMsg = new CodeMsg(HttpStatus.INTERNAL_SERVER_ERROR.value(), msg);
return new Result
}
// Constructor
private Result(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
private Result(T data, CodeMsg codeMsg) {
this.data = https://www.it610.com/article/data;
if (codeMsg != null) {
this.code = codeMsg.getCode();
this.msg = codeMsg.getMsg();
}
}
private Result(CodeMsg codeMsg) {
if (codeMsg != null) {
this.code = codeMsg.getCode();
this.msg = codeMsg.getMsg();
}
}
}
@Getter
public class CodeMsg {
private int code;
private String msg;
// 通用的错误码
public static final CodeMsg SUCCESS =new CodeMsg(HttpStatus.OK.value(), "success");
public static final CodeMsg BAD_REQUEST = new CodeMsg(HttpStatus.BAD_REQUEST.value(), "请求无效");
public static final CodeMsg SERVER_ERROR = new CodeMsg(HttpStatus.INTERNAL_SERVER_ERROR.value(), "服务端异常");
public static final CodeMsg NO_HANDLER_FOUND = new CodeMsg(HttpStatus.NOT_FOUND.value(), "未找到对应资源");
public static final CodeMsg UNAUTHORIZED = new CodeMsg(HttpStatus.UNAUTHORIZED.value(), "未认证或登录状态过期");
public static final CodeMsg FORBIDDEN = new CodeMsg(HttpStatus.FORBIDDEN.value(), "未授权");
// 自定义错误码
public static final CodeMsg PARAMETER_ERROR = new CodeMsg(4000, "参数不正确!");
/用户相关:验证码/
public static final CodeMsg CAPTCHA_EXPIRED = new CodeMsg(4001, "验证码不存在或已过期");
public static final CodeMsg CAPTCHA_INVALID = new CodeMsg(4002, "验证码错误");
/用户相关:认证授权/
public static final CodeMsg BAD_CREDENTIAL = new CodeMsg(4003, "用户名或密码错误");
public static final CodeMsg ACCOUNT_NOT_FOUND = new CodeMsg(4004, "账号不存在");
public static final CodeMsg ACCOUNT_NOT_ACTIVATED = new CodeMsg(4005, "账号未激活");
// 限流
public static final CodeMsg RATE_LIMIT = new CodeMsg(4006,"达到阈值啦!");
// 熔断
pu
blic static final CodeMsg DEGRADE = new CodeMsg(4007,"熔断啦!");
public static CodeMsg error(String msg){
return new CodeMsg(HttpStatus.BAD_REQUEST.value(),msg);
}
public CodeMsg(int code, String msg) {
this.code = code;
this.msg = msg;
}
}
[](()全局异常拦截
文章图片
默认拦截所有异常(也可自定义异常进行封装),同样通过 RestControllerAdvice
注解,实现对异常响应的统一封装。
@Slf4j
@RestControllerAdvice
public class RestExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Result exception(Exception e) {
log.error("Global exception: {}", null == e.getMessage() ? e.toString() : e.getMessage(), e);
return Result.error(CodeMsg.SERVER_ERROR.getCode(), null == e.getMessage() ? e.toString() : e.getMessage());
}
}
[](()CRUD 的 Controller
@RestController
@RequestMapping("book")
@Api(tags = "测试 Controller")
public class BookController {
@Autowired
IBookService bookService;
@GetMapping("hello")
@ApiOperation("哈喽")
public String hello() {
return "hello everyone.";
}
@GetMapping("list")
public List
return bookService.list();
}
@PostMapping("save")
public boolean save(@RequestBody Book book) {
return bookService.save(book);
}
@GetMapping("detail/{id}")
public Result detail(@PathVariable long id) {
return Result.success(bookService.getById(id));
}
@GetMapping("error")
public Result error() {
int value = https://www.it610.com/article/8 / 0;
return Result.success(value);
}
@GetMapping("page")
public Result
QueryWrapper
queryWrapper.likeRight("read_date", params.get("readDate"));
IPage
return Result.success(list);
}
}
[](()Swagger3 接口文档
文章图片
springfox-boot-starter
@Configuration
@EnableOpenApi
public class SwaggerConfig {
private static final String VERSION = "1.0.0";
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.heartsuit.readingnotes.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("SpringBoot+Swgger3.0 后端服务接口文档")
.contact(new Contact("Heartsuit", "
.description("基于 Swagger3.0 生成的接口文档")
.termsOfServiceUrl("https://blog.csdn.net/u013810234")
.license("The Apache License, Version 2.0")
.licenseUrl
.version(VERSION)
.build();
}
}
@Api(tags = "测试 Controller")
@RestController
public class HelloController {
@GetMapping("hello")
@ApiOperation("哈喽")
public String hello() {
return "Hello SpringBoot with Swagger3.0";
}
}
没错,再没其他额外的注解了,直接启动服务,然后在浏览器访问即可。
Note:
实际中我们的接口文档只会在开发环境下使用,所以一般我们会在生产环境下关闭文档。
spring:
profiles:
active: dev
springfox:
documentation:
enabled: true
springfox:
documentation:
enabled: false
[](()遇到的问题
MyBatisPlus
的SQL
日志
解决方法:
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
Long
类型的雪花算法ID
传到前端后精度丢失
解决方法:在后端 JSON
返回前统一将 Long
转为字符串。
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
return objectMapper;
}
}
解决方法:
如下,除了全局拦截的所有异常 Exception
之外,还有一个自定义的异常 CustomException
,那么,当出现 CustomException
时,当前两个异常该如何匹配呢?答案是子类异常处理器优先,即会被 customException
方法拦截,而不会被 exception
方法拦截。
@Slf4j
@RestControllerAdvice
public class RestExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Result exception(Exception e) {
log.error("Global exception: {}", null == e.getMessage() ? e.toString() : e.getMessage(), e);
return Result.error(CodeMsg.SERVER_ERROR.getCode(), null == e.getMessage() ? e.toString() : e.getMessage());
}
@ExceptionHandler(CustomException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Result customException(CustomException e) {
log.error("Custom exception: {}", null == e.getMessage() ? e.toString() : e.getMessage(), e);
return Result.error(e.getCode(), null == e.getMessage() ? e.toString() : e.getMessage());
}
}
@Getter
public class CustomException extends RuntimeException {
private static final long serialVersionUID = 1L;
private Integer code;
public CustomException(CodeMsg codeMsg) {
super(codeMsg.getMsg());
this.code = codeMsg.getCode();
}
public CustomException(Integer code, String msg){
super(msg);
this.code = code;
}
}
解决方法:
原因是我们使用 RestControllerAdvice
统一处理接口响应,导致给 Swagger 的返回值也包装了一层,最终在浏览器无法解析、渲染页面。
将 @RestControllerAdvice
改为: @RestControllerAdvice(basePackages = "com.heartsuit.*.controller")
即限制 RestControllerAdvice
的拦截范围,仅处理指定包下的接口响应。
[](()项目依赖
3.0.0
spring-boot-starter
spring-boot-starter-web
mysql-connector-java
runtime
druid-spring-boot-starter
mybatis-plus-boot-starter
springfox-boot-starter
spring-boot-devtools
runtime
lombok
spring-boot-starter-test
test
文章图片
小伙伴们有兴趣想了解内容和更多相关学习资料的请点赞收藏+评论转发+关注我,后面会有很多干货。如果在阅读过程中有疑问,请留言讨论
作者:爱好编程进阶
【spring|全栈开发之后端脚手架(SpringBoot 集成 MybatisPlus 代码生成,分页)】原文出处:全栈开发之后端脚手架:SpringBoot集成MybatisPlus代码生成,分页_Java_爱好编程进阶_InfoQ写作社区
推荐阅读
- SpringBoot|SpringBoot集成MyBatisPlus生成代码和操作
- SpringBoot|SpringBoot笔记(SpringBoot集成MyBatisPlus实战)
- Mybatis|SpringBoot整合Mybatisplus
- Springboot集成MybatisPlus、Druid
- java|SpringBoot+MyBatisPlus
- 微服务|Springboot集成Mybatisplus,轻松CRUD
- springboot系列|【springboot系列】springboot整合mybatisplus实现CRUD
- jvm|关于JVM和JDK
- java|Spring Boot干货系列((一)优雅的入门篇 | 掘金技术征文)