一、依赖
1.1 导入依赖
org.springframework.boot
spring-boot-starter-validation
org.springframework.boot
spring-boot-starter-web
org.projectlombok
lombok
true
二、目录结构
1.统一返回接口
1.1 枚举状态码定义
package com.ithwx.boot.result;
import lombok.Data;
/**
* @Author 胡文晓
* @ClassName ResultCode
* @CreateTime 2022-04-29 17:31
* @Version 1.0
* @Description: 响应码
*/
@Data
public class ResultCode {
/**
* 成功
*/
public static Integer SUCCESS = 200;
/**
* bad request
*/
public static Integer BAD_REQUEST = 400;
/**
* 未认证
*/
public static Integer UNAUTHORIZED = 401;
/**
* 无访问权限
*/
public static Integer FORBIDDEN = 403;
/**
* 接口不存在
*/
public static Integer NOT_FOUND = 404;
/**
* 方法不允许
*/
public static Integer METHOD_NOT_ALLOWED = 405;
/**
* 参数无效
*/
public static Integer PARAMS_IS_INVALID = 1001;
/**
* 参数为空
*/
public static Integer PARAMS_IS_BLANK = 1002;
/**
* 失败 服务器错误
*/
public static Integer ERROR = 500;
}
1.2统一响应体定义
package com.ithwx.boot.result;
import lombok.Setter;
/**
* @Author 胡文晓
* @ClassName ResultVO
* @CreateTime 2022-05-01 11:57
* @Version 1.0
* @Description: 统一返回值
*/
@Setter
public class ResultVO {
/**
* 是否成功
*/
private Boolean success;
/**
* 返回状态码
*/
private Integer code;
/**
* 返回信息
*/
private String message;
/**
* 返回数据
*/
private T data ;
//私有化无参构造
private ResultVO() {}
public static ResultVO success(){
ResultVO r = new ResultVO();
r.setSuccess(true);
r.setCode(ResultCode.SUCCESS);
r.setMessage("成功");
return r;
}
public static ResultVO error(){
ResultVO r = new ResultVO();
r.setSuccess(false);
r.setCode(ResultCode.ERROR);
r.setMessage("失败");
return r;
}
//链式编程
public ResultVO success(Boolean success){
this.setSuccess(success);
return this;
}
//链式编程
public ResultVO message(String message){
this.setMessage(message);
return this;
}
//链式编程
public ResultVO code(Integer code){
this.setCode(code);
return this;
}
//链式编程
public ResultVO data(T data){
this.setData(data);
return this;
}
}
2.全局异常处理
2.1自定义异常MyExceptionHandler
package com.ithwx.boot.exception;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author 胡文晓
* @ClassName MyExceptionHandler
* @CreateTime 2022-05-04 14:42
* @Version 1.0
* @Description: 自定义异常
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MyExceptionHandler extends RuntimeException {
private Integer code; //状态码
private String msg; //异常信息
}
2.2 全局异常统一处理
package com.ithwx.boot.exception;
import com.ithwx.boot.result.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @Author 胡文晓
* @ClassName GlobalExceptionHandler
* @CreateTime 2022-05-04 14:28
* @Version 1.0
* @Description: 全局统一异常处理
*/
@RestControllerAdvice
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {
//全局异常
@ExceptionHandler(Exception.class)
public ResultVO error(Exception e){
log.error("全局异常:",e.getStackTrace());
return ResultVO.error().message("执行了全局异常处理");
}
//算术异常
@ExceptionHandler(ArithmeticException.class)
public ResultVO error(ArithmeticException e){
log.error("算术异常:",e.getStackTrace());
return ResultVO.error().message("算术异常处理");
}
//自定异常
@ExceptionHandler(MyExceptionHandler.class)
public ResultVO error(MyExceptionHandler e){
log.error("自定义异常:",e.getStackTrace());
return ResultVO.error().code(e.getCode()).message(e.getMessage());
}
}
三、Knife4j配置
3.1 导入依赖
com.github.xiaoymin
knife4j-spring-boot-starter
${knife4j-spring-boot-starter.version}
3.2 创建Knife4jConfig配置类
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.util.ParameterTypes;
import org.springframework.http.ResponseEntity;
import org.springframework.plugin.core.PluginRegistry;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.resource.PathResourceResolver;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
import org.springframework.web.util.UrlPathHelper;
import springfox.documentation.annotations.ApiIgnore;
import springfox.documentation.builders.*;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.service.RequestParameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.DocumentationCache;
import springfox.documentation.spring.web.json.Json;
import springfox.documentation.spring.web.json.JsonSerializer;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.ApiResourceController;
import springfox.documentation.swagger.web.SecurityConfiguration;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper;
import springfox.documentation.swagger2.web.Swagger2ControllerWebMvc;
import springfox.documentation.swagger2.web.WebMvcSwaggerTransformationFilter;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import static org.springframework.util.MimeTypeUtils.APPLICATION_JSON_VALUE;
/**
* Swagger2 前端API配置
*
* @author chqiu
*/
@Configuration
@EnableSwagger2
@AutoConfigureAfter({WebMvcConfigurer.class})
@AllArgsConstructor
public class Knife4jConfig {
private static final String DEFAULT_PATH = "/swagger";
@Bean
public Docket createRestApi() {
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
.title("CMDB系统接口文档")
.description("CMDB系统接口文档")
.termsOfServiceUrl("http:localhsot:8080")
.contact(new Contact("南京DXC团队", "http://localhsot:8080", ""))
.version("1.0")
.build())
// 分组名称
.groupName("1.0版本").select()
// 这里指定Controller扫描包路径
.apis(RequestHandlerSelectors.basePackage("com.xxx.controller"))
.paths(PathSelectors.any())
.build()
.globalRequestParameters(buildRequestParameterList());
return docket;
}
//配置token
private List buildRequestParameterList() {
List requestParameters = new ArrayList<>();
RequestParameterBuilder requestParameterBuilder = new RequestParameterBuilder();
RequestParameter build = requestParameterBuilder.name("Authorization").description("token").in("header").required(false).build();
requestParameters.add(build);
return requestParameters;
}
/**
* SwaggerUI资源访问
*
* @param servletContext
* @param order
* @return
* @throws Exception
*/
@Bean
public SimpleUrlHandlerMapping swaggerUrlHandlerMapping(ServletContext servletContext,
@Value("${swagger.mapping.order:10}") int order) throws Exception {
SimpleUrlHandlerMapping urlHandlerMapping = new SimpleUrlHandlerMapping();
Map urlMap = new HashMap<>();
{
PathResourceResolver pathResourceResolver = new PathResourceResolver();
pathResourceResolver.setAllowedLocations(new ClassPathResource("META-INF/resources/webjars/"));
pathResourceResolver.setUrlPathHelper(new UrlPathHelper());
ResourceHttpRequestHandler resourceHttpRequestHandler = new ResourceHttpRequestHandler();
resourceHttpRequestHandler.setLocations(Arrays.asList(new ClassPathResource("META-INF/resources/webjars/")));
resourceHttpRequestHandler.setResourceResolvers(Arrays.asList(pathResourceResolver));
resourceHttpRequestHandler.setServletContext(servletContext);
resourceHttpRequestHandler.afterPropertiesSet();
//设置新的路径
urlMap.put(DEFAULT_PATH + "/webjars/**", resourceHttpRequestHandler);
}
{
PathResourceResolver pathResourceResolver = new PathResourceResolver();
pathResourceResolver.setAllowedLocations(new ClassPathResource("META-INF/resources/"));
pathResourceResolver.setUrlPathHelper(new UrlPathHelper());
ResourceHttpRequestHandler resourceHttpRequestHandler = new ResourceHttpRequestHandler();
resourceHttpRequestHandler.setLocations(Arrays.asList(new ClassPathResource("META-INF/resources/")));
resourceHttpRequestHandler.setResourceResolvers(Arrays.asList(pathResourceResolver));
resourceHttpRequestHandler.setServletContext(servletContext);
resourceHttpRequestHandler.afterPropertiesSet();
//设置新的路径
urlMap.put(DEFAULT_PATH + "/**", resourceHttpRequestHandler);
}
urlHandlerMapping.setUrlMap(urlMap);
//调整DispatcherServlet关于SimpleUrlHandlerMapping的排序
urlHandlerMapping.setOrder(order);
return urlHandlerMapping;
}
/**
* SwaggerUI接口访问
*/
@Controller
@ApiIgnore
@RequestMapping(DEFAULT_PATH)
public static class SwaggerResourceController implements InitializingBean {
private final ApiResourceController apiResourceController;
private final DocumentationCache documentationCache;
private final ServiceModelToSwagger2Mapper mapper;
private final JsonSerializer jsonSerializer;
private final PluginRegistry transformations;
private static final String HAL_MEDIA_TYPE = "application/hal+json";
private Swagger2ControllerWebMvc swagger2ControllerWebMvc;
public SwaggerResourceController(ApiResourceController apiResourceController, DocumentationCache documentationCache, ServiceModelToSwagger2Mapper mapper, JsonSerializer jsonSerializer, PluginRegistry transformations) {
this.apiResourceController = apiResourceController;
this.documentationCache = documentationCache;
this.mapper = mapper;
this.jsonSerializer = jsonSerializer;
this.transformations = transformations;
}
@Override
public void afterPropertiesSet() throws Exception {
swagger2ControllerWebMvc = new Swagger2ControllerWebMvc(documentationCache, mapper, jsonSerializer, transformations);
}
/**
* Swagger API首页地址
*
* @return 首页地址
*/
@RequestMapping
public ModelAndView index() {
return new ModelAndView("redirect:" + DEFAULT_PATH + "/doc.html");
}
@RequestMapping("/swagger-resources/configuration/security")
@ResponseBody
public ResponseEntity securityConfiguration() {
return apiResourceController.securityConfiguration();
}
@RequestMapping("/swagger-resources/configuration/ui")
@ResponseBody
public ResponseEntity uiConfiguration() {
return apiResourceController.uiConfiguration();
}
@RequestMapping("/swagger-resources")
@ResponseBody
public ResponseEntity> swaggerResources() {
return apiResourceController.swaggerResources();
}
@RequestMapping(value = "/v2/api-docs", method = RequestMethod.GET, produces = {APPLICATION_JSON_VALUE, HAL_MEDIA_TYPE})
@ResponseBody
public ResponseEntity getDocumentation(
@RequestParam(value = "group", required = false) String swaggerGroup,
HttpServletRequest servletRequest) {
return swagger2ControllerWebMvc.getDocumentation(swaggerGroup, servletRequest);
}
}
}
四、启动类
4.1后台打印接口地址
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import java.net.InetAddress;
import java.net.UnknownHostException;
@SpringBootApplication
@Slf4j
@MapperScan("com.dxc.cmdb.mapper")
@EnableTransactionManagement
public class CMDBMain {
public static void main(String[] args) throws UnknownHostException {
ConfigurableApplicationContext run = SpringApplication.run(CMDBMain.class, args);
Environment env = run.getEnvironment();
String ip = InetAddress.getLocalHost().getHostAddress();
String port = env.getProperty("server.port");
//String path = env.getProperty("server.servlet.context-path");
log.info("\n----------------------------------------------------------\n\t" +
"Application is running! Access URLs:\n\t" +
"Local: \t\thttp://localhost:" + port + "/\n\t" +
"External: \thttp://" + ip + ":" + port +"/\n\t" +
"Swagger文档:\thttp://" + ip + ":" + port +"/cmdb/swagger/doc.html\n" +
"----------------------------------------------------------");
}
}
五、mybatis-plus
5.1 导入依赖
com.baomidou
mybatis-plus-boot-starter
3.5.1
5.2 yam配置
mybatis-plus:
global-config:
db-config:
logic-delete-value: 1 #逻辑删除值
logic-not-delete-value: 0 #逻辑未删除值
mapper-locations: classpath:mapper/*.xml
configuration:
#打印sql
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
注意启动类要加:@MapperScan("com.xxx.xxx.mapper")
5.3 代码生成器
5.3.1 导入依赖
org.apache.velocity
velocity-engine-core
2.0
com.baomidou
mybatis-plus-generator
3.3.2
5.3.2 新建代码生成器类
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import java.util.ArrayList;
import java.util.List;
public class CodeGenerator {
public static void main(String[] args) {
// 1、创建代码生成器
AutoGenerator mpg = new AutoGenerator();
// 2、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
//项目存储路径
//String path ="D:\\ideaworkspace\\cmdb";
gc.setOutputDir(projectPath + "/src/main/java");
//gc.setAuthor("itwenxiao");
gc.setOpen(false); //生成后是否打开资源管理器
gc.setFileOverride(false); //重新生成时文件是否覆盖
//gc.setServiceName("%sService"); //去掉Service接口的首字母I
gc.setMapperName("I%sMapper");
gc.setIdType(IdType.ASSIGN_ID); //主键策略
gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
gc.setSwagger2(true);//开启Swagger2模式
mpg.setGlobalConfig(gc);
// 3、数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://127.0.1:3306/cmdb?serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
// 4、包配置
PackageConfig pc = new PackageConfig();
pc.setParent("com.dxc.cmdb");
//pc.setModuleName("eduservice"); //模块名
// pc.setController("controller");
// pc.setEntity("entity");
// pc.setService("service");
// pc.setMapper("mapper");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
//如果模板引擎是 velocity
String templatePath = "/templates/mapper.xml.vm";
// 自定义输出配置
List focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
return projectPath + "/src/main/resources/mapper/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 5、策略配置
StrategyConfig strategy = new StrategyConfig();
//对应数据库表名,如果有多表操作就用逗号隔开
strategy.setInclude("sys_cluster_template");
strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
strategy.setRestControllerStyle(true); //restful api风格控制器
strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
mpg.setStrategy(strategy);
// 6、执行
mpg.execute();
}
}