java企业级权限系统开发-权限开发工具

mybatis逆向工程,同意返回封住哪个类、springmvc全局异常处理、校验工具-validator,Json转换工具,获取spring上下文,http请求监听等。

1. mybatis generator

pom中增加插件:

<build>
    <plugins>
      <plugin>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-maven-plugin</artifactId>
        <version>1.3.2</version>
        <configuration>
          <verbose>true</verbose>
          <overwrite>true</overwrite>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
</build>

生成文件GeneratorConfig.xml

注意要对自己的数据库的jar包位置、用户名、密码等进行修改

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
<generatorConfiguration>

    <!--classPathEntry:数据库的JDBC驱动 -->
    <classPathEntry
            location="D:\apache-maven-3.5.0\mysql-connector-java-5.1.34.jar" />

    <context id="MysqlTables" targetRuntime="MyBatis3">

        <!-- 注意这里面的顺序确定的,不能随变更改 -->
        <!-- 自定义的分页插件 <plugin type="com.deppon.foss.module.helloworld.shared.PaginationPlugin"/> -->

        <!-- 可选的(0 or 1) -->
        <!-- 注释生成器 -->
        <commentGenerator>
            <!-- 是否去除自动生成的注释 true:是 : false:否 -->
            <property name="suppressAllComments" value="true" />
        </commentGenerator>

        <!-- 必须的(1 required) -->
        <!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/jimin"
                        userId="root" password="123456">
        </jdbcConnection>

        <!-- 可选的(0 or 1) -->
        <!-- 类型转换器或者加类型解析器 -->
        <!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer true,把JDBC DECIMAL 和
            NUMERIC 类型解析为java.math.BigDecimal -->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>


        <!-- 必须的(1 required) -->
        <!-- java模型生成器 -->
        <!-- targetProject:自动生成代码的位置 -->
        <javaModelGenerator targetPackage="com.njupt.model"
                            targetProject="F:\gitee\permission\src\main\java"
        >
            <!-- TODO enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="true" />
            <!-- 从数据库返回的值被清理前后的空格 -->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>

        <!-- 必须的(1 required) -->
        <!-- map xml 生成器 -->
        <sqlMapGenerator targetPackage="mapper"
                         targetProject="F:\gitee\permission\src\main\resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>

        <!-- 可选的(0 or 1) -->
        <!-- mapper 或者就是dao接口生成器 -->
        <javaClientGenerator targetPackage="com.njupt.dao"
                             targetProject="F:\gitee\permission\src\main\java"
                             type="XMLMAPPER">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>

        <!-- 必须的(1...N) -->
        <!-- pojo 实体生成器 -->
        <!-- tableName:用于自动生成代码的数据库表;domainObjectName:对应于数据库表的javaBean类名 -->
        <!-- schema即为数据库名 可不写 -->
        <table  tableName="sys_user" domainObjectName="SysUser"
                enableInsert="true" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
                enableSelectByExample="false" selectByExampleQueryId="false">
            <!-- 忽略字段 可选的(0 or 1) -->
            <!-- <ignoreColumn column="is_use" /> -->
            <!--//无论字段是什么类型,生成的类属性都是varchar。 可选的(0 or 1) 测试无效 -->
            <!-- <columnOverride column="city_code" jdbcType="VARCHAR" /> -->
        </table>
        <table  tableName="sys_role_user" domainObjectName="SysRoleUser"
                enableInsert="true" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
                enableSelectByExample="false" selectByExampleQueryId="false">
        </table>
        <table  tableName="sys_role_acl" domainObjectName="SysRoleAcl"
                enableInsert="true" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
                enableSelectByExample="false" selectByExampleQueryId="false">
        </table>
        <table  tableName="sys_role" domainObjectName="SysRole"
                enableInsert="true" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
                enableSelectByExample="false" selectByExampleQueryId="false">
        </table>
        <table  tableName="sys_log" domainObjectName="SysLog"
                enableInsert="true" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
                enableSelectByExample="false" selectByExampleQueryId="false">
            <columnOverride column="old_value" jdbcType="VARCHAR" />
            <columnOverride column="new_value" jdbcType="VARCHAR" />
        </table>
        <table  tableName="sys_dept" domainObjectName="SysDept"
                enableInsert="true" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
                enableSelectByExample="false" selectByExampleQueryId="false">
        </table>
        <table  tableName="sys_acl_module" domainObjectName="SysAclModule"
                enableInsert="true" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
                enableSelectByExample="false" selectByExampleQueryId="false">
        </table>
        <table  tableName="sys_acl" domainObjectName="SysAcl"
                enableInsert="true" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
                enableSelectByExample="false" selectByExampleQueryId="false">
        </table>
    </context>
</generatorConfiguration>

最后mybatis-generator:generate -e进行运行。

2. 项目的json返回和jsp返回

先写一个统一的返回封装类:

@Data
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.setMsg(msg);
        jsonData.setData(object);
        return jsonData;
    }

    public static JsonData success(Object object){
        JsonData jsonData = new JsonData(true);
        jsonData.setData(object);
        return jsonData;
    }

    public static JsonData success(){
        return new JsonData(true);
    }

    public static JsonData fail(String msg){
        JsonData jsonData = new JsonData(false);
        jsonData.setMsg(msg);
        return jsonData;
    }

    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;
    }
}

然后规定以.json结尾的就是json数据,以.page结尾的就是普通返回jsp的数据。

3. 全局异常处理

那么普通情况下,不会出现问题,但是在出现异常的时候呢,我们不希望在页面出现一坨异常信息,怎么办?这个时候就需要有一个全局异常类:

全局异常类也要分.json和.page两种:

@Slf4j
@Component
public class SpringExceptionResolver implements HandlerExceptionResolver{

    @Override
    public ModelAndView resolveException(javax.servlet.http.HttpServletRequest request,
                                         javax.servlet.http.HttpServletResponse response,
                                         Object handler, Exception e) {
        String url = request.getRequestURI().toString();
        ModelAndView mv;
        String defaultMsg = "system error";

        //.json
        if(url.endsWith(".json")){
            if(e instanceof PermissionException || e instanceof ParamException){
                //是自定义的异常
                JsonData result = JsonData.fail(e.getMessage());
                mv = new ModelAndView("jsonView",result.toMap());//jsonView与spring-servlet中呼应
            }else {
                log.error("unkonen exception,url:"+url,e);
                JsonData result = JsonData.fail(defaultMsg);
                mv = new ModelAndView("jsonView",result.toMap());
            }
        }else if(url.endsWith(".page")){//.page
            log.error("unkonen exception,url:"+url,e);
            JsonData result = JsonData.fail(defaultMsg);
            mv = new ModelAndView("exception",result.toMap());//去jsp目录下找一个叫exception的页面
        }else {
            log.error("unkonen exception,url:"+url,e);
            JsonData result = JsonData.fail(defaultMsg);
            mv = new ModelAndView("jsonView",result.toMap());
        }
        return mv;
    }
}

注意不要忘记被springmvc管理:

<bean id="springExceptionResolver" class="com.njupt.common.SpringExceptionResolver"/>

对于PermissionException:

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);
    }

    protected PermissionException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

4. BeanValidator

要对数据进行校验,我们用hibernate-validator来实现注解校验,先引入pom:

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

然后写一个接受验证错误的信息类BeanValidator:

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.njupt.exception.ParamException;
import org.apache.commons.collections.MapUtils;

import javax.validation.*;
import java.util.*;

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 validatorResult = validator.validate(t,groups);
        if(validatorResult.isEmpty()){
            return Collections.EMPTY_MAP;
        }else {
            LinkedHashMap errors = Maps.newLinkedHashMap();
            Iterator iterator = validatorResult.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.EMPTY_MAP;
            }
            Object object = iterator.next();
            errors = validate(object,new Class[0]);
        }while (errors.isEmpty());
        return errors;
    }

    public static Map<String,String> validateObject(Object first,Object... objects){
        if(objects != null && objects.length > 0){
            return validateList(Lists.asList(first,objects));
        }else {
            return validate(first,new Class[0]);
        }
    }

    //这里不返回具体的参数校验错误信息,而是直接抛出异常
    public static void check(Object param) throws ParamException{
        Map<String,String> map = BeanValidator.validateObject(param);
//        if(map != null && map.entrySet().size()>0){
//            throw new ParamException(map.toString());
//        }
        if(MapUtils.isEmpty(map)){
            throw new ParamException(map.toString());
        }
    }
}

对于直接抛出异常,我们需要些一个ParamException,也是直接继承RuntimeExceptionin即可。

我们对其进行测试一下:

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

在TestController中,测试一下,不携带参数,看是否会自动报出空错误:

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

访问:http://localhost:8080/test/validate.json

看控制台是否出现:msg->不能为空;id->不能为null这些信息,出现了则说明我们的校验已经生效了。

5. JsonMapper

json与对象之间的互相转换。

<!--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>
<dependency>
  <groupId>joda-time</groupId>
  <artifactId>joda-time</artifactId>
  <version>2.3</version>
</dependency>

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
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.type.JavaType;
import org.codehaus.jackson.type.TypeReference;
import java.io.IOException;
import java.text.SimpleDateFormat;

@Slf4j
public class JsonMapper {
private static ObjectMapper objectMapper = new ObjectMapper();

static {
    //所有字段都列入进行转换
    objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.ALWAYS);
    //取消默认转换timestamp形式
    objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS,false);
    //忽略空bean转json的错误
    objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS,false);
    //统一时间的格式
    objectMapper.setDateFormat(new SimpleDateFormat(DateTimeUtil.STANDARD_FORMAT));
    //忽略json存在属性,但是java对象不存在属性的错误
    objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES,false);
}

/**
 * 序列化方法,将对象转为字符串
 * @param obj
 * @param <T>
 * @return
 */
public static <T> String obj2String(T obj){
    if(obj == null){
        return null;
    }
    try {
        return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj);
    } catch (IOException e) {
        log.warn("parse object to string error",e);
        return null;
    }
}

/**
 * 序列化方法,同上,只是输出的格式是美化的,便于测试
 * @param obj
 * @param <T>
 * @return
 */
public static <T> String obj2StringPretty(T obj){
    if(obj == null){
        return null;
    }
    try {
        return obj instanceof String ? (String) obj : objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
    } catch (IOException e) {
        log.warn("parse object to string error",e);
        return null;
    }
}

/**
 * 比较简单的反序列化的方法,将字符串转为单个对象
 * @param str
 * @param clazz
 * @param <T>
 * @return
 */
public static <T> T String2Obj(String str,Class<T> clazz){
    if(StringUtils.isEmpty(str) || clazz == null){
        return null;
    }
    try {
        return clazz.equals(String.class)?(T)str:objectMapper.readValue(str,clazz);
    } catch (IOException e) {
        log.warn("parse string to obj error",e);
        return null;
    }
}

/**
 * 复杂对象的反序列化(通用)
 * @param str
 * @param typeReference
 * @param <T>
 * @return
 */
public static <T> T Str2Obj(String str, TypeReference typeReference){
    if(StringUtils.isEmpty(str) || typeReference == null){
        return null;
    }
    try {
        return (T) (typeReference.getType().equals(String.class)?str:objectMapper.readValue(str,typeReference));
    } catch (IOException e) {
        log.warn("parse string to obj error",e);
        return null;
    }
}

/**
 * 第二种方式实现复杂对象的反序列化
 * @param str
 * @param collectionClass
 * @param elementClasses
 * @param <T>
 * @return
 */
public static <T> T Str2Obj(String str,Class<?> collectionClass,Class<?>... elementClasses){
    JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClass,elementClasses);
    try {
        return objectMapper.readValue(str,javaType);
    } catch (IOException e) {
        log.warn("parse string to obj error",e);
        return null;
    }
}

}

这里我直接还有复杂对象的转换,我顺便也将时间处理的工具类也放进去了:

public class DateTimeUtil {
    //joda-time

    //str->Date
    //Date->str
    public static final String STANDARD_FORMAT = "yyyy-MM-dd HH:mm:ss";



    public static Date strToDate(String dateTimeStr, String formatStr){
        DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(formatStr);
        DateTime dateTime = dateTimeFormatter.parseDateTime(dateTimeStr);
        return dateTime.toDate();
    }

    public static String dateToStr(Date date,String formatStr){
        if(date == null){
            return StringUtils.EMPTY;
        }
        DateTime dateTime = new DateTime(date);
        return dateTime.toString(formatStr);
    }

    //固定好格式
    public static Date strToDate(String dateTimeStr){
        DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(STANDARD_FORMAT);
        DateTime dateTime = dateTimeFormatter.parseDateTime(dateTimeStr);
        return dateTime.toDate();
    }

    public static String dateToStr(Date date){
        if(date == null){
            return StringUtils.EMPTY;
        }
        DateTime dateTime = new DateTime(date);
        return dateTime.toString(STANDARD_FORMAT);
    }

    public static void main(String[] args) {
        System.out.println(DateTimeUtil.dateToStr(new Date(),"yyyy-MM-dd HH:mm:ss"));
        System.out.println(DateTimeUtil.strToDate("2010-01-01 11:11:11","yyyy-MM-dd HH:mm:ss"));

    }
}

6. spring上下文获取

如何获取spring上下文?

@Component("applicationContextHelper")
public class ApplicationContextHelper implements ApplicationContextAware{
    private static ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        applicationContext = context;
    }

    public static <T> T popBean(Class<T> clazz){
        if(applicationContext == null){
            return null;
        }
        return applicationContext.getBean(clazz);
    }

    public static <T> T popBean(String name,Class<T> clazz){
        if(applicationContext == null){
            return null;
        }
        return applicationContext.getBean(name,clazz);
    }
}

注意要在spring初始化的时候就加载这个类,所以在spring-servlet中添加:

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

可以进行测试一下:

@RequestMapping("/validate1.json")
@ResponseBody
public JsonData validate1(TestVo testVo) throws ParamException{
    SysAclModuleMapper moduleMapper = ApplicationContextHelper.popBean(SysAclModuleMapper.class);
    SysAclModule module = moduleMapper.selectByPrimaryKey(1);
    log.info(JsonMapper.obj2String(module));
    BeanValidator.check(testVo);
    return JsonData.success("hello validate");
}

7. Http请求监听

就是mvc拦截器的应用了,我们在这里可以记录他访问的url是什么,还有就是一个接口的相应时间。都记录与日志中。

@Slf4j
public class HttpInterceptor extends HandlerInterceptorAdapter{
    private static final String STRAT_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("preHandle,url:{},params:{}",url, JsonMapper.obj2String(parameterMap));
        long start = System.currentTimeMillis();
        request.setAttribute(STRAT_TIME,start);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        String url = request.getRequestURI().toString();
        long start = (long)request.getAttribute(STRAT_TIME);
        long end = System.currentTimeMillis();
        log.info("afterCompletion,preHandle,url:{},time cost:{}",url, end-start);
    }
}

在spring-servlet中也要配置拦截器。

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

猜你喜欢

转载自blog.csdn.net/sunweiguo1/article/details/80342655