Springboot代碼生成器V2.21版本更新——升級(jí)相關(guān)依賴版本杉女、加入全局響應(yīng)處理壹哺、使用注解控制登錄和日志記錄等

前言

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

由于工作和生活等多方面的影響垢啼,半年多沒有更新博客私爷,代碼生成器也沒有繼續(xù)維護(hù),后來(lái)不斷有朋友發(fā)私信催我更新膊夹,并且提出相關(guān)的優(yōu)化建議衬浑,今天終于得空把代碼生成器根據(jù)朋友們的建議整體改良了一下,以后我也會(huì)盡量保持健康的更新速度放刨,希望可以對(duì)大家有所幫助工秩!

全局跨域配置

之前生成的代碼每一個(gè)controller都會(huì)加上@CrossOrigin,現(xiàn)在則采用了整體的跨域配置进统,前者可以靈活控制助币,后者更加簡(jiǎn)單直接,但跨域一般都是為了前后端聯(lián)調(diào)方便螟碎,所以采用了后者眉菱,因?yàn)檎江h(huán)境上的前后臺(tái)一般會(huì)使用nginx統(tǒng)一做轉(zhuǎn)發(fā)處理,把跨域的接口寫成調(diào)本域的接口掉分,然后將這些接口轉(zhuǎn)發(fā)到真正的請(qǐng)求地址俭缓,也就不存在跨域的問題。
有一點(diǎn)需要注意(與跨域無(wú)關(guān))酥郭,現(xiàn)在新版goole瀏覽器加強(qiáng)了安全方面的監(jiān)控华坦,主要是為了防止注入類攻擊,如果發(fā)現(xiàn)訪問應(yīng)用的地址和應(yīng)用的父級(jí)地址不同源不从,登錄時(shí)會(huì)無(wú)法設(shè)置cookie惜姐,如果使用session控制用戶的登錄,就會(huì)出現(xiàn)獲取不到seesion的問題椿息,因?yàn)闊o(wú)法設(shè)置cookie歹袁,就沒有了seesionId坷衍,導(dǎo)致登錄無(wú)效。對(duì)此也有相應(yīng)的解決辦法:
1.打開Chrome設(shè)置条舔,將chrome://flags/#same-site-by-default-cookies禁用枫耳,然后重啟瀏覽器即可;
2.采用token代替cokkie做驗(yàn)證逞刷,也就是我們常用的使用redis保存token做驗(yàn)證的方式嘉涌。
跨域配置的代碼如下:

/**
 * 跨域配置
 *
 * @author zrx
 */
@Configuration
public 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));
        //過濾前會(huì)在攔截器之前執(zhí)行,就不會(huì)被攔截器影響
        bean.setOrder(0);
        return bean;
    }
}

添加控制登錄和日志記錄的注解

在實(shí)際的項(xiàng)目開發(fā)中夸浅,往往一個(gè)項(xiàng)目后臺(tái)有很多api仑最,有些api需要登錄鑒權(quán),有些則不需要帆喇,為了靈活控制警医,采用注解的方式來(lái)對(duì)此進(jìn)行控制,原理很簡(jiǎn)單坯钦,在攔截器中獲取請(qǐng)求方法的注解信息预皇,如果注解存在則進(jìn)行登錄驗(yàn)證,如不存在則直接放行婉刀,相關(guān)代碼如下:

/**
 * 該注解用于REST API
 * 如果一個(gè)API需要用戶用戶登錄吟温,添加此注解
 *
 * @author zrx
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @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;
                    }
                    // 預(yù)請(qǐng)求
                    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\":\"無(wú)授權(quán)訪問,請(qǐng)先登錄\"}");
                        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/**");
    }

使用方法也及其簡(jiǎn)單突颊,直接在controller的方法上添加此注解即可鲁豪,例:

    /**
     * 查詢
     *
     * @return
     */
    @ApiOperation(value = "查詢")
    //添加此注解則表明調(diào)用此方法需要登錄方可調(diào)用
    @LoginRequired
    @PostMapping(value = "/select")
    public List<TestTableEntity> select(@RequestBody TestTableEntity entity) {
        return service.select(entity);
    }

日志記錄注解與登錄注解同理,添加日志記錄注解可以實(shí)現(xiàn)方法級(jí)別的日志記錄律秃,使用方法同上爬橡,代碼如下:

/**
 * 需要記錄的日志的注解
 * 在需要記錄日志的controller上添加該注解,可以記錄日志
 *
 * @author zrx
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RecordLog {
    String value() default "";
}

@Aspect
@Component
public 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("======= 開始執(zhí)行:" + className + " — " + methodName + " ========");
        Object obj = pjp.proceed();
        logger.info("======= 執(zhí)行結(jié)束:" + className + " — " + methodName + " ========");
        return obj;
    }
}

響應(yīng)統(tǒng)一處理

之前代碼生成器的響應(yīng)已經(jīng)做了一層抽取棒动,把返回的信息統(tǒng)一封裝到了對(duì)象當(dāng)中糙申,但沒有做到完全解耦,現(xiàn)在對(duì)響應(yīng)做了全局的進(jìn)一步封裝船惨,controller只需要書寫業(yè)務(wù)代碼柜裸,不需要再去new一個(gè)響應(yīng)體對(duì)象,進(jìn)一步降低了耦合度掷漱,對(duì)于程序異常只需要throw相應(yīng)的異常即可粘室,統(tǒng)一處理類會(huì)封裝異常信息給予前臺(tái)用戶提示,代碼如下:

@Slf4j
@ControllerAdvice
@ResponseBody
public class AllExceptionHandler implements ResponseBodyAdvice {

    @Override
    public boolean supports(MethodParameter returnType, Class clazz) {
        return null == returnType.getMethodAnnotation(NoPack.class);
    }
    /**
     * 響應(yīng)返回之前對(duì)響應(yīng)內(nèi)容進(jìn)行包裝
     */
    @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;
    }
    ....
    /**
     * 普通業(yè)務(wù)異常
     *
     * @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());
    }
    /**
     * 其他錯(cuò)誤
     *
     * @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);
    }
}

/**
 * 請(qǐng)求響應(yīng)體
 *
 * @author zrx
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public 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
 *
 * 如果一個(gè)API的返回不需要被ResponseWrapper包裝卜范,添加此注解
 * 
 * @author zrx
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface NoPack {

}

代碼如上所示,實(shí)現(xiàn)ResponseBodyAdvice接口中的beforeBodyWrite方法鹿榜,即可對(duì)返回的內(nèi)容進(jìn)行包裝海雪,spring中無(wú)時(shí)無(wú)刻都在滲透著aop的核心思想锦爵。
如果不想包裝響應(yīng)內(nèi)容,則可以在controller的方法上添加NoPack注解來(lái)實(shí)現(xiàn)奥裸,原理與上面提到的登錄注解一樣:實(shí)現(xiàn)ResponseBodyAdvice的supports方法险掀,如果不存在NoPack注解,則對(duì)響應(yīng)內(nèi)容做包裝湾宙,spring已經(jīng)幫我們實(shí)現(xiàn)了整體的功能樟氢,我們只需要重寫方法加入相關(guān)業(yè)務(wù)即可。

swagger優(yōu)化

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>

其他更新

除了以上更新之外,生成器還升級(jí)了mysql的版本依賴至8.0.18伟恶,springboot版本至2.2.6.RELEASE碴开,spring版本至5.2.5.RELEASE,添加了lombok支持博秫,修復(fù)了一些已知的bug潦牛,下一步準(zhǔn)備加入權(quán)限配置的相關(guān)代碼生成,進(jìn)一步完善現(xiàn)有功能挡育。

生成的代碼展示

v2.21版
代碼展示

結(jié)語(yǔ)

本次更新介紹到這里就結(jié)束了巴碗,其中響應(yīng)的統(tǒng)一處理個(gè)人認(rèn)為還算是比較有意義的,也感謝大家提出的寶貴意見即寒,工作忙橡淆,加上生活上的瑣事,更新可能不會(huì)太及時(shí)蒿叠,還望見諒明垢,下次再見啦!

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末市咽,一起剝皮案震驚了整個(gè)濱河市痊银,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌施绎,老刑警劉巖溯革,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異谷醉,居然都是意外死亡致稀,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門俱尼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)抖单,“玉大人,你說我怎么就攤上這事∶妫” “怎么了耍休?”我有些...
    開封第一講書人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)货矮。 經(jīng)常有香客問我羊精,道長(zhǎng),這世上最難降的妖魔是什么囚玫? 我笑而不...
    開封第一講書人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任喧锦,我火速辦了婚禮,結(jié)果婚禮上抓督,老公的妹妹穿的比我還像新娘燃少。我一直安慰自己,他們只是感情好本昏,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開白布供汛。 她就那樣靜靜地躺著,像睡著了一般涌穆。 火紅的嫁衣襯著肌膚如雪怔昨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,096評(píng)論 1 291
  • 那天宿稀,我揣著相機(jī)與錄音趁舀,去河邊找鬼。 笑死祝沸,一個(gè)胖子當(dāng)著我的面吹牛矮烹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播罩锐,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼奉狈,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了涩惑?” 一聲冷哼從身側(cè)響起仁期,我...
    開封第一講書人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎竭恬,沒想到半個(gè)月后跛蛋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡痊硕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年赊级,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片岔绸。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡理逊,死狀恐怖橡伞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情挡鞍,我是刑警寧澤骑歹,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布预烙,位于F島的核電站墨微,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏扁掸。R本人自食惡果不足惜翘县,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望谴分。 院中可真熱鬧锈麸,春花似錦、人聲如沸牺蹄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)沙兰。三九已至氓奈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鼎天,已是汗流浹背舀奶。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留斋射,地道東北人育勺。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像罗岖,于是被迫代替她去往敵國(guó)和親涧至。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容