Java 企業級權限管理項目筆記(六) - - - 項目準備與核心輔導工具類開發

權限管理開發-準備html

1、核心類生成 - Mybatis generate

功能 : MyBatis官方提供了逆向工程 mybatis-generator,能夠針對數據庫表自動生成MyBatis執行所須要的代碼(如Mapper.java、Mapper.xml、POJO)。mybatis-generator 有三種用法:命令行、eclipse插件、maven插件。java

一、添加generate插件到permission工程中   mysql

   

根據插件包路徑對配置文件 generator.xml 配置文件進行相應修改:web

第一點:spring

修改成mysql-connector-java.5.1.34.jar所在的路徑sql

第二點:數據庫

修改數據庫鏈接配置apache

<jdbcConnection driverClass="com.mysql.jdbc.Driver"				
	connectionURL="jdbc:mysql://192.168.254.111:3306/test1?characterEncoding=utf8"
			userId="root"
			password="root">  <!-- 2 -->

第三點到第五點:json

配置生成的類的包及保存路徑api

第六點:

配置要生成的表及對應的表的實體類名稱。

二、執行生成命令:

J:\permission\permission\generator>java -jar mybatis-generator-core-1.3.2.jar -configfile generator.xml
MyBatis Generator finished successfully.

執行結果:

                

2、項目接口定義 -json,page

後臺收到前臺的請求時,通常有兩種請求,一種是數據請求,一種頁面請求;返回請求結果時,除了返回請求的結果時,還須要返回相關的狀態,用於返回異常以及異常描述。

建立JsonData用於封裝數據

package com.webcode.springboot.common; import lombok.Getter; import lombok.Setter; import java.util.HashMap; import java.util.Map; /** * @ClassName JsonData * @Description TODO * @Author wushaopei * @Date 2019/10/11 14:05 * @Version 1.0 */ @Setter @Getter public class JsonData { private boolean ret; private String msg; private Object data; public JsonData(boolean ret) { this.ret = ret; } //須要傳數據和異常狀態 public static JsonData success(Object object,String msg){ JsonData jsonData = new JsonData(true); jsonData.data = object; jsonData.msg = msg; return jsonData; } //只須要傳數據 public static JsonData success(Object object){ JsonData jsonData = new JsonData(true); jsonData.data = object; return jsonData; } //不須要數據,只須要傳狀態 public static JsonData success(){ return new JsonData(true); } //請求失敗 public static JsonData fail(String msg){ JsonData jsonData = new JsonData(false); jsonData.msg = msg; return jsonData; } } 

ret爲true表明請求結果爲所須要的數據內容,爲false時表明請求被拒絕或權限不足、異常等,配合msg進行描述。

3、接口請求全局異常處理-設計與驗證

添加相關依賴:

<!--jsp-->
    <dependency>
      <groupId>org.apache.tomcat</groupId>
      <artifactId>jsp-api</artifactId>
      <version>6.0.36</version>
    </dependency>

建立異常攔截類:

/** * @ClassName SpringExceptionResolver * @Description TODO * @Author wushaopei * @Date 2019/10/11 14:27 * @Version 1.0 */ @Slf4j public class SpringExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object o, Exception ex) { String url = request.getRequestURL().toString(); String[] split = url.split(""); String s = split[split.length - 1]; int i = s.indexOf("/"); if(s.indexOf("/")==0){ StringBuffer sb = new StringBuffer(url); url= sb.substring(0, sb.length() - 1); System.out.println(url); } ModelAndView mv; //聲明一個modelandvie,用於返回 String defaultMsg = "System error"; //這裏區別對數據請求和頁面請求進行的處理 //.json , .page ,請求的區分根據其後綴進行區分 //這裏要求項目中全部請求json數據,都使用.json結尾 if (url.endsWith(".json")){ }else{ } return null; } } 

這裏使用@Slf4j進行日誌的輸出。

建立自定義異常類 PermissionException:

package com.webcode.springboot.exception; /** * @ClassName PermissionException * @Description TODO * @Author wushaopei * @Date 2019/10/11 14:36 * @Version 1.0 */ public class PermissionException extends RuntimeException { public PermissionException() { super(); } public PermissionException(String message) { super(message); } public PermissionException(String message, Throwable cause) { super(message, cause); } public PermissionException(Throwable cause) { super(cause); } public PermissionException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } } 

JsonData.java 補充:

public Map<String, Object> toMap(){ HashMap<String, Object> result = new HashMap<>(); result.put("ret",ret); result.put("msg",msg); result.put("data",data); return result; }

建立exception.jsp 異常描述頁面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Exception</title> </head> <body> </body> </html> 

完整的異常攔截:

@Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object o, Exception ex) { String url = request.getRequestURL().toString(); ModelAndView mv; //聲明一個modelandvie,用於返回 String defaultMsg = "System error"; //這裏區別對數據請求和頁面請求進行的處理 //.json , .page ,請求的區分根據其後綴進行區分 //這裏要求項目中全部請求json數據,都使用.json結尾 if (url.endsWith(".json")){ //當前異常是否匹配自定義異常攔截的實例或子類實例 if(ex instanceof PermissionException){ //只要異常是咱們建立出來的時,才處理本身拋出來的異常 JsonData fail = JsonData.fail(ex.getMessage()); mv = new ModelAndView("jsonView",fail.toMap()); }else { log.error("unknown json exception, url:" + url, ex); JsonData fail = JsonData.fail(defaultMsg); mv = new ModelAndView("jsonView",fail.toMap()); } }else if(url.endsWith(".page")){ // 這裏咱們要求項目中全部請求page頁面,都使用.page結尾 log.error("unknown page exception, url:" + url, ex); JsonData fail = JsonData.fail(defaultMsg); mv = new ModelAndView("exception",fail.toMap()); }else { JsonData fail = JsonData.fail(defaultMsg); mv = new ModelAndView("jsonView",fail.toMap()); } return mv; }

爲何 ModelAndView的構造器加入 ".toMap()"方法:

               

由圖中ModelAndView的源碼可知,其構造器默認對數據使用Map進行封裝,因此爲了符合ModelAndView的代碼規範,這裏對JsonData的異常返回結果進行Map的轉化。

而第一個參數「jsonView」對應spring-servlet.xml中的配置:

Bean配置:

<bean class="com.webcode.springboot.common.SpringExceptionResolver"/>

接口測試異常攔截:

 

使用普通的RuntimeException建立異常對象:

@Controller @RequestMapping("/test") @Slf4j public class TestController { @RequestMapping("/hello.json") @ResponseBody public JsonData hello(){ log.info("hello"); throw new RuntimeException("test exception"); } }

             

使用自定義的PermissionException建立異常對象:

@RequestMapping("/hello.json") @ResponseBody public JsonData hello(){ log.info("hello"); throw new PermissionException("test exception"); // return JsonData.success("hello,permission"); }

             

4、校驗工具-BeanValidator開發

一、添加環境依賴:

<!--validator-->
    <dependency>
      <groupId>javax.validation</groupId>
      <artifactId>validation-api</artifactId>
      <version>1.1.0.Final</version>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>5.2.4.Final</version>
    </dependency>

二、建立BeanValidator類

public class BeanValidator { private static ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); public static <T> Map<String,String> validate(T t, Class... groups){ Validator validator = validatorFactory.getValidator(); Set validateResult = validator.validate(t,groups); if (validateResult.isEmpty()){ return Collections.emptyMap(); }else { LinkedHashMap errors = Maps.newLinkedHashMap(); Iterator iterator = validateResult.iterator(); while (iterator.hasNext()){ ConstraintViolation violation = (ConstraintViolation) iterator.next(); errors.put(violation.getPropertyPath().toString(),violation.getMessage()); } return errors; } } public static Map<String,String> validateList(Collection<?> collection){ Preconditions.checkNotNull(collection); Iterator<?> iterator = collection.iterator(); Map errors; do { if (!iterator.hasNext()){ return Collections.emptyMap(); } Object object = iterator.next(); errors = validate(object,new Class[0]); }while (errors.isEmpty()); return errors; } }

建立TestVo類:

@Getter @Setter public class TestVo { @NotBlank private String msg; @NotNull private Integer id; } 

接口測試:

@ResponseBody @RequestMapping("/validate.json") public JsonData validate(TestVo vo){ log.info("validate"); try { Map<String, String> map = BeanValidator.validateObject(vo); if (map != null && map.entrySet().size() > 0){ for (Map.Entry<String, String> entry : map.entrySet()) { log.info("{}->{}",entry.getKey(),entry.getValue()); } } }catch (Exception e){ } return JsonData.success("test validate"); }

沒有傳參的狀況下,控制檯打印異常報警日誌:

帶參數的請求:

http://localhost/test/validate.json/?id=1&msg=123123

沒有異常報警:

BeanValidator的使用:

說明:BeanValidator是基於註解的,

基於@NotBlank、@NotNull、@NotEmpty等註解

@Getter @Setter public class TestVo { @NotBlank private String msg; @NotNull(message = "id不能夠爲空") @Max(value = 10,message = "id 不能大於10") @Min(value = 0,message = "id 至少大於等於0") private Integer id; @NotEmpty private List<String> str; } 

對Object參數進行判空,不作結果返回:

public static void check(Object param){ //參數異常處理 Map<String, String> map = BeanValidator.validateObject(param); if(MapUtils.isNotEmpty(map)){ throw new ParamException(map.toString()); } }

MapUtils用於判空,須要引入相關依賴:

<!--tools-->
    <dependency>
      <groupId>commons-collections</groupId>
      <artifactId>commons-collections</artifactId>
      <version>3.2.2</version>
    </dependency>
    <dependency>
      <groupId>commons-codec</groupId>
      <artifactId>commons-codec</artifactId>
      <version>1.10</version>
    </dependency>

建立參數異常處理類 ParamException.java

public class ParamException extends RuntimeException { public ParamException() { public ParamException(String message) { super(message); } public ParamException(String message, Throwable cause) { super(message, cause); } public ParamException(Throwable cause) { super(cause); } public ParamException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } } 

測試:

@ResponseBody @RequestMapping("/validate2.json") public JsonData validate2(TestVo vo){ log.info("validate2"); BeanValidator.check(vo); return JsonData.success("test validate2"); }

5、權限管理開發 - 工具相關

校驗工具 - validator

Json轉換工具 - jackson convert

導入相關依賴:

<!--jackson-->
    <dependency>
      <groupId>org.codehaus.jackson</groupId>
      <artifactId>jackson-core-asl</artifactId>
      <version>1.9.13</version>
    </dependency>
    <dependency>
      <groupId>org.codehaus.jackson</groupId>
      <artifactId>jackson-mapper-asl</artifactId>
      <version>1.9.13</version>
    </dependency>

建立JsonMapper.java類,該類能夠把類轉換爲一個json對象,也能夠把類轉換爲咱們指定的類對象。

package com.webcode.springboot.util; import lombok.extern.slf4j.Slf4j; import org.codehaus.jackson.map.DeserializationConfig; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.SerializationConfig; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.codehaus.jackson.map.ser.impl.SimpleFilterProvider; import org.codehaus.jackson.type.TypeReference; /** * @ClassName JsonMapper * @Description TODO * @Author wushaopei * @Date 2019/10/11 22:56 * @Version 1.0 */ @Slf4j public class JsonMapper { private static ObjectMapper objectMapper = new ObjectMapper(); static { //config objectMapper.disable(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES); objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS,false); objectMapper.setFilters(new SimpleFilterProvider().setFailOnUnknownId(false)); objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_EMPTY); } public static <T> String obj2String(T src){ if (src == null){ return null; } try { return src instanceof String ? (String) src : objectMapper.writeValueAsString(src); }catch (Exception e){ log.warn("parse object to String exception",e); return null; } } public static <T> T string2Obj(String src, TypeReference<T> typeReference){ if (src == null || typeReference == null){ return null; } try { return (T) (typeReference.getType().equals(String.class)? src : objectMapper.readValue(src,typeReference)); }catch (Exception e){ log.warn("parse String to Object exception,String:{},TypeReference<T>:{},error{}",src,typeReference.getType()); return null; } } } 

6、獲取Spring上下文工具-ApplicationContextHelper開發

建立一個獲取上下文的類:

package com.webcode.springboot.common; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; /** * @ClassName ApplicationContextHelper * @Description TODO * @Author wushaopei * @Date 2019/10/11 23:19 * @Version 1.0 */ //該註解將當前類交給Spring進行管理 @Component("applicationContextHelper") public class ApplicationContextHelper implements ApplicationContextAware{ private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { applicationContext = applicationContext; } public static <T> T popBean(Class<T> clazz){ //若是applicationContext爲空,則返回一個空值 if(applicationContext == null){ return null; } //不然,就返回當前applicationContext的Bean映射的類 return applicationContext.getBean(clazz); } public static <T> T popBean(String name,Class<T> clazz){ //若是applicationContext爲空,則返回一個空值 if(applicationContext == null){ return null; } //不然,就返回name和當前applicationContext的Bean映射的類 return applicationContext.getBean(name,clazz); } } 

配置對應的Bean:

<bean class="com.webcode.springboot.common.ApplicationContextHelper" lazy-init="false"/> 

測試:經過DB進行驗證操做:

@ResponseBody @RequestMapping("/validate3.json") public JsonData valitade3(TestVo vo){ log.info("validate"); SysAclModuleMapper moduleMapper = ApplicationContextHelper.popBean(SysAclModuleMapper.class); SysAclModule module = moduleMapper.selectByPrimaryKey(1); BeanValidator.check(vo); return JsonData.success("test validate3"); }

            ​\

7、 Http請求先後監聽工具-HttpInterceptor開發

建立HttpInterceptor.java類,繼承HandlerInterceptorAdapter類,對Http請求先後進行監聽

@Slf4j public class HttpInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String url = request.getRequestURI().toString(); Map parameterMap = request.getParameterMap(); log.info("request start. url:{}, params:{}",url, JsonMapper.obj2String(parameterMap)); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { String url = request.getRequestURI().toString(); Map parameterMap = request.getParameterMap(); log.info("request finished. url:{}, params:{}",url,JsonMapper.obj2String(parameterMap)); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { String url = request.getRequestURI(); Map parameterMap = request.getParameterMap(); log.info("request completed. url:{}, params:{}",url,JsonMapper.obj2String(parameterMap)); } }

配置Bean被Spring進行管理:

<mvc:interceptors>
        <bean class="com.webcode.springboot.common.HttpInterceptor"/>
    </mvc:interceptors>

測試:

@ResponseBody @RequestMapping("/validate3.json") public JsonData valitade3(TestVo vo){ log.info("validate"); SysAclModuleMapper moduleMapper = ApplicationContextHelper.popBean(SysAclModuleMapper.class); SysAclModule module = moduleMapper.selectByPrimaryKey(1); log.info(JsonMapper.obj2String(module)); BeanValidator.check(vo); return JsonData.success("test validate3"); }

任何請求在被進行處理前,會先被preHandle方法進行處理,若是該方法處理經過,就會執行postHandle方法,任何請求執行結束後都會被afterCompletion方法進行處理

記錄請求開始到結束所花費的時間

private static final String START_TIME = "requestStartTime"; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String url = request.getRequestURI().toString(); Map parameterMap = request.getParameterMap(); log.info("request start. url:{}, params:{}",url, JsonMapper.obj2String(parameterMap)); long start = System.currentTimeMillis(); request.setAttribute(START_TIME, start); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { String url = request.getRequestURI().toString(); Map parameterMap = request.getParameterMap(); long start = (Long) request.getAttribute(START_TIME); long end = System.currentTimeMillis(); log.info("request finished. url:{}, cost:{}",url,end - start); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { String url = request.getRequestURI().toString(); long start = (Long) request.getAttribute(START_TIME); long end = System.currentTimeMillis(); log.info("request completed. url:{}, cost:{}",url,end - start); }

監聽器除了能夠進行登陸時間的監控外,還可進行用戶的cookie、session、登陸是否過時等進行監聽。

相關文章
相關標籤/搜索