Springboot代码生成器V2.21版本升级——更新相关依赖版本、加入全局响应解决、使用注解控制登录和日志记录等

作者 : 开心源码 本文共7806个字,预计阅读时间需要20分钟 发布时间: 2022-05-14 共282人阅读

前言

生成器下载地址:http://www.zrxlh.top:8088/coreCode/.
源码地址:https://gitee.com/zrxjava/codeMan

因为工作和生活等多方面的影响,半年多没有升级博客,代码生成器也没有继续维护,后来不断有朋友发私信催我升级,并且提出相关的优化建议,今天终于得空把代码生成器根据朋友们的建议整体改良了一下,以后我也会尽量保持健康的升级速度,希望可以对大家有所帮助!

全局跨域配置

之前生成的代码每一个controller都会加上@CrossOrigin,现在则采用了整体的跨域配置,前者可以灵活控制,后者更加简单直接,但跨域一般都是为了前后台联调方便,所以采用了后者,由于正式环境上的前后端一般会使用nginx统一做转发解决,把跨域的接口写成调本域的接口,而后将这些接口转发到真正的请求地址,也就不存在跨域的问题。
有一点需要注意(与跨域无关),现在新版goole浏览器增强了安全方面的监控,主要是为了防止注入类攻击,假如发现访问应用的地址和应用的父级地址不同源,登录时会无法设置cookie,假如使用session控制客户的登录,就会出现获取不到seesion的问题,由于无法设置cookie,就没有了seesionId,导致登录无效。对此也有相应的处理办法:
1.打开Chrome设置,将chrome://flags/#same-site-by-default-cookies禁用,而后重启浏览器就可;
2.采用token代替cokkie做验证,也就是我们常用的使用redis保存token做验证的方式。
跨域配置的代码如下:

/** * 跨域配置 * * @author zrx */@Configurationpublic class CorsConfig {    @Bean    public FilterRegistrationBean<CorsFilter> corsFilter() {        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();        CorsConfiguration config = new CorsConfiguration();        config.setAllowCredentials(true);        config.addAllowedOrigin("*");        config.addAllowedHeader("token");        config.addAllowedHeader("Content-Type");        config.addAllowedMethod("GET");        config.addAllowedMethod("POST");        config.addAllowedMethod("PUT");        config.addAllowedMethod("DELETE");        config.addAllowedMethod("OPTIONS");        config.setMaxAge(1000L * 60 * 60);        source.registerCorsConfiguration("/**", config);        FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));        //过滤前会在阻拦器之前执行,就不会被阻拦器影响        bean.setOrder(0);        return bean;    }}

增加控制登录和日志记录的注解

在实际的项目开发中,往往一个项目后端有很多api,有些api需要登录鉴权,有些则不需要,为了灵活控制,采用注解的方式来对此进行控制,原理很简单,在阻拦器中获取请求方法的注解信息,假如注解存在则进行登录验证,如不存在则直接放行,相关代码如下:

/** * 该注解用于REST API * 假如一个API需要客户客户登录,增加此注解 * * @author zrx */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@Documentedpublic @interface LoginRequired {}@Override    public void addInterceptors(InterceptorRegistry registry) {        registry.addInterceptor(new HandlerInterceptor() {            @Override            public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)                    throws Exception {                if (handler instanceof HandlerMethod) {                    HandlerMethod handlerMethod = (HandlerMethod) handler;                    LoginRequired loginRequired = handlerMethod.getMethodAnnotation(LoginRequired.class);                    if (null == loginRequired) {                        return true;                    }                    // 预请求                    if (RequestMethod.OPTIONS.name().equals(request.getMethod())) {                        return true;                    }                    HttpSession session = request.getSession();                    User user = (User) session.getAttribute("user");                    if (user == null) {                        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));                        response.setHeader("Access-Control-Allow-Methods", "*");                        response.setHeader("Access-Control-Max-Age", "3600");                        response.setHeader("Access-Control-Allow-Credentials", "true");                        response.setContentType("application/json; charset=utf-8");                        response.setCharacterEncoding("utf-8");                        PrintWriter pw = response.getWriter();                        pw.write("{\"code\":" + HttpServletResponse.SC_UNAUTHORIZED + ",\"status\":\"no\",\"msg\":\"无受权访问,请先登录\"}");                        pw.flush();                        pw.close();                        return false;                    }                }                return true;            }        }).addPathPatterns("/**").excludePathPatterns("/login", "/register", "/login/doLogin", "/user/register",                "/mystatic/**", "/druid/**", "/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**");    }

使用方法也及其简单,直接在controller的方法上增加此注解就可,例:

    /**     * 查询     *     * @return     */    @ApiOperation(value = "查询")    //增加此注解则表明调用此方法需要登录方可调用    @LoginRequired    @PostMapping(value = "/select")    public List<TestTableEntity> select(@RequestBody TestTableEntity entity) {        return service.select(entity);    }

日志记录注解与登录注解同理,增加日志记录注解可以实现方法级别的日志记录,使用方法同上,代码如下:

/** * 需要记录的日志的注解 * 在需要记录日志的controller上增加该注解,可以记录日志 * * @author zrx */@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface RecordLog {    String value() default "";}@Aspect@Componentpublic class LogAopAspect {    private static final Logger logger = LoggerFactory.getLogger(LogAopAspect.class);    @Around("@annotation(bootdemo.core.annotation.RecordLog)")    public Object process(ProceedingJoinPoint pjp) throws Throwable {        Class<?> currentClass = pjp.getTarget().getClass();        MethodSignature signature = (MethodSignature) (pjp.getSignature());        String className = currentClass.getSimpleName();        String methodName = currentClass.getMethod(signature.getName(), signature.getParameterTypes()).getName();        logger.info("======= 开始执行:" + className + " — " + methodName + " ========");        Object obj = pjp.proceed();        logger.info("======= 执行结束:" + className + " — " + methodName + " ========");        return obj;    }}

响应统一解决

之前代码生成器的响应已经做了一层抽取,把返回的信息统一封装到了对象当中,但没有做到完全解耦,现在对响应做了全局的进一步封装,controller只要要书写业务代码,不需要再去new一个响应体对象,进一步降低了耦合度,对于程序异常只要要throw相应的异常就可,统一解决类会封装异常信息给予前端客户提醒,代码如下:

@Slf4j@ControllerAdvice@ResponseBodypublic class AllExceptionHandler implements ResponseBodyAdvice {    @Override    public boolean supports(MethodParameter returnType, Class clazz) {        return null == returnType.getMethodAnnotation(NoPack.class);    }    /**     * 响应返回之前对响应内容进行包装     */    @Override    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {        if (MediaType.APPLICATION_JSON.equals(selectedContentType) || MediaType.APPLICATION_JSON_UTF8.equals(selectedContentType)) {            Method method = (Method) returnType.getExecutable();            if (ResponseEntity.class.equals(method.getReturnType())) {                return body;            }            if (null == body) {                return ResponseResult.success();            }            if (body instanceof ResponseResult) {                return body;            }            return ResponseResult.success(body);        }        return body;    }    ....    /**     * 普通业务异常     *     * @param ex     * @return     */    @ExceptionHandler(BusinessException.class)    public ResponseResult businessExceptionHandler(HttpServletResponse response, BusinessException ex) {        log.error(ex.getMessage(), ex);        response.setStatus(ResponseStatus.BUSINESS_EXCEPTION.hCode);        return ResponseResult.failed(ex.getCode(), ex.getMessage());    }    /**     * 其余错误     *     * @param ex     * @return     */    @ExceptionHandler({Exception.class})    public ResponseResult exception(HttpServletResponse response, Exception ex) {        log.error(ResponseStatus.OTHER_EXCEPTION.valueLog, ex);        response.setStatus(ResponseStatus.OTHER_EXCEPTION.hCode);        return ResponseResult.failed(ResponseStatus.OTHER_EXCEPTION.bCode, ResponseStatus.OTHER_EXCEPTION.valueZh);    }}/** * 请求响应体 * * @author zrx */@Data@Builder@AllArgsConstructor@NoArgsConstructorpublic class ResponseResult implements Serializable {    private static final long serialVersionUID = 6041766238120354185L;    private int code;    private String status;    private String msg;    private Object data;    public static ResponseResult success() {        return success(null);    }    public static ResponseResult success(Object data) {        return ResponseResult.builder()                .status(ResponseStatus.SUCCESS.valueEn)                .msg(ResponseStatus.SUCCESS.valueZh)                .code(ResponseStatus.SUCCESS.bCode)                .data(data)                .build();    }    public static ResponseResult failed() {        return failed("失败");    }    public static ResponseResult failed(String msg) {        return failed(ResponseStatus.FAILED.bCode, msg);    }    public static ResponseResult failed(int code, String msg) {        return ResponseResult.builder()                .status(ResponseStatus.FAILED.valueEn)                .msg(msg)                .code(code)                .build();    }}   /** * 该注解用于REST API * * 假如一个API的返回不需要被ResponseWrapper包装,增加此注解 *  * @author zrx */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@Documentedpublic @interface NoPack {}

代码如上所示,实现ResponseBodyAdvice接口中的beforeBodyWrite方法,就可对返回的内容进行包装,spring中无时无刻都在渗透着aop的核心思想。
假如不想包装响应内容,则可以在controller的方法上增加NoPack注解来实现,原理与上面提到的登录注解一样:实现ResponseBodyAdvice的supports方法,假如不存在NoPack注解,则对响应内容做包装,spring已经帮我们实现了整体的功能,我们只要要重写方法加入相关业务就可。

swagger优化

swagger官方的样式比较丑,所以增加了新的swagger样式依赖,样式如下:

swagger

依赖如下:

<dependency>            <groupId>io.springfox</groupId>            <artifactId>springfox-swagger2</artifactId>            <version>2.9.2</version>        </dependency>        <dependency>            <groupId>io.springfox</groupId>            <artifactId>springfox-swagger-ui</artifactId>            <version>2.9.2</version>        </dependency>        <dependency>            <groupId>com.github.xiaoymin</groupId>            <artifactId>swagger-bootstrap-ui</artifactId>            <version>1.9.5</version>        </dependency>

其余升级

除了以上升级之外,生成器还更新了mysql的版本依赖至8.0.18,springboot版本至2.2.6.RELEASE,spring版本至5.2.5.RELEASE,增加了lombok支持,修复了少量已知的bug,下一步准备加入权限配置的相关代码生成,进一步完善现有功能。

生成的代码展现

v2.21版代码展现

结语

本次升级详情到这里就结束了,其中响应的统一解决个人认为还算是比较有意义的,也感谢大家提出的宝贵意见,工作忙,加上生活上的琐事,升级可能不会太及时,还望见谅,下次再见啦!

生成器下载地址:http://www.zrxlh.top:8088/coreCode/.
源码地址:https://gitee.com/zrxjava/codeMan

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Springboot代码生成器V2.21版本升级——更新相关依赖版本、加入全局响应解决、使用注解控制登录和日志记录等

发表回复