商城项目
一、拦截器封装结果集
1.1自定义响应结果集注解ResponseResult
定义注解、设置变量(默认值为true)、添加元注解
//标明该注解的生命周期是编译到class阶段
@Retention(RetentionPolicy.RUNTIME)
//标明该注解只能写在方法或类上面
@Target({ElementType.METHOD,ElementType.TYPE})
//标明该注解可以随着被定义的java文件生成到JavaDoc文档当中
@Documented
//标明该注解的子类的声明部分也能自动拥有该注解
@Inherited
public @interface ResponseResult {
public boolean value() default true;
}
1.2新建结果集拦截器ResultInterceptor
新建结果集拦截器、继承拦截器适配器、编写前置拦截器preHandle
@Component
public class ResultInterceptor extends HandlerInterceptorAdapter {
private static final String RESPONSE_RESULT_ANN = "RESPONSE-RESULT-ANN";
//判断当前请求的接口映射的方法是否使用了我们的自定义ResponseResult注解,把信息存储在了request域中
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//ResourceHttpRequestHandler是用来处理静态资源的;而HandlerMethod则是springMVC中用@Controller声明的一个bean及对应的处理方法
if(handler instanceof HandlerMethod){//如果拦截器继承HandlerMethod
HandlerMethod handlerMethod = (HandlerMethod) handler;//将handler转换成HandlerMethod类型
Class<?> beanType = handlerMethod.getBeanType();//获取拦截的类
Method method = handlerMethod.getMethod();//获取拦截的方法
//如果拦截的方法不存在,类是否有自定义的响应结果集注解
if(method != null){//如果拦截的方法存在
if(method.isAnnotationPresent(ResponseResult.class)){//方法上是否有自定义的响应结果集注解
request.setAttribute(RESPONSE_RESULT_ANN,method.getAnnotation(ResponseResult.class));
}
}
if(beanType.isAnnotationPresent(ResponseResult.class)){//类上是否有自定义的响应结果集注解
request.setAttribute(RESPONSE_RESULT_ANN,beanType.getAnnotation(ResponseResult.class));
}
}
return true;
}
}
1.3新建结果集处理器ResultHandler
新建结果集处理器、实现ResponseBodyAdvice、判断当前的返回结果集是否需要重写、重写结果集
@RestControllerAdvice
//使用 ResponseBodyAdvice 拦截Controller方法默认返回参数,统一处理返回值/响应体
public class ResultHandler implements ResponseBodyAdvice<Object> {
private static final String RESPONSE_RESULT_ANN = "RESPONSE-RESULT-ANN";
//判断当前的返回结果集是否需要重写
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
ResponseResult attribute = (ResponseResult) request.getAttribute(RESPONSE_RESULT_ANN);
if(attribute == null){
return false;
}
return attribute.value();
}
//重写
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
if(o instanceof GlobalException){//全局异常处理(业务)
GlobalException globalException = (GlobalException) o;
return ResultUtil.fail(globalException.getResultEnum());
}
if(o instanceof Exception){//系统异常处理
Exception exception = (Exception) o;
return ResultUtil.fail(ResultEnum.EXCEPTION,exception.getMessage());
}
if(o instanceof Result){//系统返回正常的结果集
return o;
}
return ResultUtil.success(ResultEnum.SUCCESS,o);
}
}
1.4编写测试
增加测试方法、添加注解@ResponseResult
@ResponseResult
@ApiOperation(value = "元注解结果集")
@GetMapping("/test4")
public Result test4(){
return new Result("自定义元注解结果集成功");
}
注意添加Result的构造方法
//自定义元注解
public Result(Object data){
this.data = data;
}
二、在线接口文档Knife4j
2.1导入依赖
knife4j
<!--knife4j-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.7</version>
</dependency>
2.2编写配置文件
编写Knife4jConfig、apiInfo用户信息、分组名称、扫描包路径
@Configuration
@EnableSwagger2WebMvc
public class Knife4jConfig {
@Bean(value = "defaultApi2")
public Docket defaultApi2() {
Docket docket=new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
.title("shop-pxxy api文档")
.description("# shop-pxxy restful APIs")
.termsOfServiceUrl("http://www.xx.com/")
.contact(new Contact("沈金勇","https://gitee.com/ShenJinyong","438217638@qq.com"))
.version("1.0")
.build())
//分组名称
.groupName("2.X版本")
.select()
//这里指定Controller扫描包路径
.apis(RequestHandlerSelectors.basePackage("com.qf.controller"))
.paths(PathSelectors.any())
.build();
return docket;
}
}
2.3解决静态资源访问问题
WebConfig
@Configuration
public class WebConfig implements WebMvcConfigurer {
//解决knife4j静态资源访问不到的问题
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("doc.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
2.4访问测试
http://localhost:8080/doc.html
三、逆向工程
3.1导入依赖
mybatis-plus、generator自动生成器、volocity模板引擎
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<!--generator-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<!--velocity模板引擎-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
3.2编写逆向生成代码
新建代码生成器GodeGenerator类、全局配置、数据源配置、包配置、策略配置
public class CodeGenerator {
/**
* 读取控制台内容
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotBlank(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}
/*
* 逆向工程,自动生成代码
* */
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");//项目路径
gc.setOutputDir(projectPath + "/src/main/java");//文件路径
gc.setAuthor("沈金勇");//作者
gc.setOpen(false);//是否打开文件
gc.setSwagger2(true); //是否开启Swagger2注解
mpg.setGlobalConfig(gc);//把全局配置添加到代码生成器中
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/shop?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC");//数据库地址地址
dsc.setDriverName("com.mysql.cj.jdbc.Driver");//驱动
dsc.setUsername("root");//用户名
dsc.setPassword("123456");//密码
mpg.setDataSource(dsc);//把数据源配置添加到代码生成器中
// 包配置
PackageConfig pc = new PackageConfig();
pc.setParent("com.qf");//包名
mpg.setPackageInfo(pc);//把包配置添加到代码生成器中
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);//表开启驼峰命名
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//字段开启驼峰命名
strategy.setEntityLombokModel(true);//是否开启实体类lombok模型
strategy.setRestControllerStyle(true);//是否开启RestController
strategy.setInclude(scanner("表名, 多个英文逗号分割").split(","));//有那些表需要自动生成
strategy.setControllerMappingHyphenStyle(true);
mpg.setStrategy(strategy);//把策略配置添加到代码生成器中
// 执行代码生成器
mpg.execute();
}
}
3.3测试
启动测试、添加mapper扫描
@SpringBootApplication
@MapperScan("com.qf.mapper")
public class ShopPxxyApplication {
public static void main(String[] args) {
SpringApplication.run(ShopPxxyApplication.class, args);
}
}