Browse Source

维保项功能更新

wanghaicheng 5 years ago
parent
commit
3b5b8dc858

+ 24 - 28
lift-enterprise-service/src/main/java/cn/com/ty/lift/enterprise/option/controller/MaintenanceOptionController.java

@@ -32,10 +32,10 @@ public class MaintenanceOptionController {
     private final MaintenanceOptionServiceImpl optionService;
 
     /**
+     * 分页获取维保项列表
+     *
      * @param req 页码 页大小
      * @return cn.com.xwy.boot.web.dto.RestResponse
-     * @description 分页获取维保项列表
-     * @date 2019/12/19 9:21
      */
     @PostMapping("/list")
     public RestResponse list(@RequestBody OptionReq req) {
@@ -45,8 +45,7 @@ public class MaintenanceOptionController {
                         .in("mt_company_id", 10086L, req.getMtCompanyId())
                         .in(req.getType() != null, "type", type(req))
                         .eq(req.getLiftCategory() != null, "lift_category", req.getLiftCategory())
-                        .orderByDesc("mt_company_id")
-        );
+                        .eq(req.getStatus() != null, "status", req.getStatus()));
         if (page.getRecords().isEmpty()) {
             return RestResponse.success();
         }
@@ -61,10 +60,14 @@ public class MaintenanceOptionController {
      */
     @PostMapping("/options")
     public RestResponse options(@RequestBody OptionReq req) {
-        Integer liftType = req.getLiftCategory();
+        Integer category = req.getLiftCategory();
         String sort = null;
-        if (liftType.equals(3)) {
+        if (category == 4 || category == 5) {
+            req.setLiftCategory(3);
+        }
+        if (category == 3) {
             sort = "-1,1";
+            req.setLiftCategory(4);
         }
         List<MaintenanceOption> options = optionService.list(
                 new QueryWrapper<MaintenanceOption>()
@@ -73,8 +76,7 @@ public class MaintenanceOptionController {
                         .in(req.getType() != null, "type", type(req))
                         .eq(req.getLiftCategory() != null, "lift_category", req.getLiftCategory())
                         .eq(req.getStatus() != null, "status", req.getStatus())
-                        .in(sort != null, "sort", sort)
-        );
+                        .in(sort != null, "sort", sort));
         if (options.isEmpty()) {
             return RestResponse.success();
         }
@@ -89,45 +91,39 @@ public class MaintenanceOptionController {
      */
     @PostMapping("/add")
     public RestResponse add(@RequestBody MaintenanceOption option) {
-        if (optionService.save(option)) {
-            return RestResponse.success(option.getId(), "成功");
-        }
-        return RestResponse.fail();
+        return RestResponse.success(optionService.save(option));
     }
 
     /**
+     * 判断是否默认维保项,不是默认维保项才可以更新
+     *
      * @param option 维保项信息
      * @return RestResponse
-     * @description 判断是否默认维保项,不是默认维保项才可以更新
-     * @date 2019/12/19 10:03
      */
     @PostMapping("/modify")
     public RestResponse modify(@RequestBody MaintenanceOption option) {
+        Long mtCompanyId = optionService.getById(option.getId()).getMtCompanyId();
         //10086L是固定数据的公司id
-        if (option.getMtCompanyId().equals(10086L)) {
-            return RestResponse.fail("默认维保项无法编辑");
+        if (option.getMtCompanyId().equals(mtCompanyId) || option.getMtCompanyId().equals(10086L)) {
+            return RestResponse.success(optionService.updateById(option));
         }
-        if (optionService.updateById(option)) {
-            return RestResponse.success(null, "成功");
-        }
-        return RestResponse.failParam();
+        return RestResponse.fail("默认维保项无法编辑");
     }
 
     /**
+     * 判断是否是默认维保项,不是默认的维保项才可以删除
+     *
      * @param option 维保项id
      * @return RestResponse
-     * @description 判断是否是默认维保项,不是默认的维保项才可以删除
      */
     @PostMapping("/delete")
     public RestResponse delete(@RequestBody MaintenanceOption option) {
-        //10086L是平台的团队id
-        if (option.getMtCompanyId().equals(10086L)) {
-            return RestResponse.fail("默认维保项无法删除");
-        }
-        if (optionService.removeById(option.getId())) {
-            return RestResponse.success(null, "成功");
+        Long mtCompanyId = optionService.getById(option.getId()).getMtCompanyId();
+        //10086L是固定数据的公司id
+        if (option.getMtCompanyId().equals(mtCompanyId) || option.getMtCompanyId().equals(10086L)) {
+            return RestResponse.success(optionService.removeById(option.getId()));
         }
-        return RestResponse.fail();
+        return RestResponse.fail("默认维保项无法删除");
     }
 
     /**

+ 2 - 2
lift-enterprise-service/src/main/java/cn/com/ty/lift/enterprise/option/dao/entity/MaintenanceOption.java

@@ -55,8 +55,8 @@ public class MaintenanceOption implements Serializable {
     private Integer type;
 
     /**
-     * 电梯类型  '(1乘客梯/载货电梯 2液压梯 3扶梯/人行道 4杂物梯)'
-     * '电梯类别(1:曳引梯;2:液压梯;3:杂物梯;4:自动扶梯;5:自动人行道)'
+     * 电梯类别(1:曳引梯;2:液压梯;3:杂物梯;4:自动扶梯;5:自动人行道)
+     * 电梯类型(1乘客梯/载货电梯 2液压梯 3扶梯/人行道 4杂物梯)
      */
     @TableField("lift_category")
     private Integer liftCategory;

+ 0 - 13
lift-enterprise-service/src/main/java/cn/com/ty/lift/enterprise/option/service/impl/MaintenanceOptionServiceImpl.java

@@ -3,7 +3,6 @@ package cn.com.ty.lift.enterprise.option.service.impl;
 import cn.com.ty.lift.enterprise.option.dao.entity.MaintenanceOption;
 import cn.com.ty.lift.enterprise.option.dao.mapper.MaintenanceOptionMapper;
 import cn.com.ty.lift.enterprise.option.service.MaintenanceOptionService;
-import cn.com.xwy.boot.web.dto.RestResponse;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.springframework.stereotype.Service;
 
@@ -17,16 +16,4 @@ import org.springframework.stereotype.Service;
  */
 @Service
 public class MaintenanceOptionServiceImpl extends ServiceImpl<MaintenanceOptionMapper, MaintenanceOption> implements MaintenanceOptionService {
-
-    public RestResponse delete(MaintenanceOption option) {
-        //0是系统默认维保项
-        option = this.getById(option.getId());
-        if (option.getMtCompanyId().equals(0L)) {
-            return RestResponse.fail("默认维保项无法删除");
-        }
-        if (this.removeById(option.getId())) {
-            return RestResponse.success(null, "成功");
-        }
-        return RestResponse.fail();
-    }
 }

+ 43 - 0
upload/pom.xml

@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>lift-server</artifactId>
+        <groupId>cn.com.ty</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>upload</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.ty</groupId>
+            <artifactId>lift-common</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <mainClass>com.Application</mainClass>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 11 - 0
upload/src/main/java/com/Application.java

@@ -0,0 +1,11 @@
+package com;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+    public static void main(String[] args) {
+        SpringApplication.run(Application.class, args);
+    }
+}

+ 116 - 0
upload/src/main/java/com/controller/common/CommonController.java

@@ -0,0 +1,116 @@
+package com.controller.common;
+
+import cn.com.ty.lift.common.utils.ValuePool;
+import cn.com.ty.lift.common.verify.Verify;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.*;
+
+/**
+ * 文件上传接口
+ */
+@Slf4j
+@AllArgsConstructor
+@RestController
+@RequestMapping("common")
+public class CommonController {
+    private static final String DateInPath = "yyyy/MM/dd";
+    private SystemConfiguration systemConfiguration;
+
+    /**
+     * 批量上传多个文件
+     *
+     * @param files 文件列表
+     * @return RestResponse
+     */
+    @PostMapping("uploads")
+    public RestResponse uploads(@RequestParam("files") MultipartFile[] files) {
+        Verify.notTrue(Objects.isNull(files) || files.length == 0, Verify.Upload.fileDataMissing);
+        try {
+            Map<String, MultipartFile> fileMap = new HashMap<>();
+            //1 先解析文件格式
+            for (MultipartFile file : files) {
+                String fileName = handleFile(file);
+                if (StrUtil.isEmpty(fileName)) {
+                    return RestResponse.fail(Verify.Upload.fileFormatNotSupport);
+                }
+                fileMap.put(fileName, file);
+            }
+            //2 批量上传
+            List<String> urls = new ArrayList<>();
+            for (Map.Entry<String, MultipartFile> entry : fileMap.entrySet()) {
+                String url = systemConfiguration.build().putObject(entry.getKey(), entry.getValue().getBytes());
+                log.info("上传文件,文件URL: {}", url);
+                Verify.notNull(url, Verify.Upload.fileUploadFail);
+                urls.add(url);
+            }
+            return RestResponse.success(urls);
+        } catch (Exception e) {
+            log.error("上传文件异常", e);
+            return RestResponse.fail(Verify.Upload.fileUploadFail);
+        }
+    }
+
+    /**
+     * 上传单个文件
+     *
+     * @param file 上传的文件
+     * @return RestResponse
+     */
+    @PostMapping("upload")
+    public RestResponse upload(@RequestParam("file") MultipartFile file) {
+        Verify.notTrue(Objects.isNull(file) || file.isEmpty(), Verify.Upload.fileDataMissing);
+        try {
+            String fileName = handleFile(file);
+            if (StrUtil.isEmpty(fileName)) {
+                return RestResponse.fail(Verify.Upload.fileFormatNotSupport);
+            }
+            String url = systemConfiguration.build().putObject(fileName, file.getBytes());
+            log.info("上传文件,文件URL: {}", url);
+            return RestResponse.success(url);
+        } catch (Exception e) {
+            log.error("上传文件异常", e);
+            return RestResponse.fail(Verify.Upload.fileUploadFail);
+        }
+    }
+
+    /**
+     * 校验文件大小,文件格式,生成新文件名
+     *
+     * @param file the {@link MultipartFile} to upload
+     * @return the name string of the file.
+     */
+    private String handleFile(MultipartFile file) {
+        Verify.notTrue(Objects.isNull(file) || file.isEmpty(), Verify.Upload.fileDataMissing);
+        // 获取文件名,带后缀
+        String originalFilename = file.getOriginalFilename();
+        log.info("上传文件,原文件名:{}", originalFilename);
+        // 获取文件的后缀格式
+        int lastDotIndex = originalFilename.lastIndexOf(ValuePool.DOT);
+        Verify.notTrue(-1 == lastDotIndex, "文件名解析不到文件格式");
+        String fileSuffix = originalFilename.substring(lastDotIndex).toLowerCase();
+        Verify.notNull(fileSuffix, Verify.Upload.fileFormatIllegal);
+        long fileSize = file.getSize();
+        if (StrUtil.equalsAny(fileSuffix, Verify.Upload.pics)) {
+            Verify.notTrue(fileSize > Verify.Upload.maxSizePic, "文件大小不超过" + Verify.Upload.maxSizePicDesc);
+        } else if (StrUtil.equalsAny(fileSuffix, Verify.Upload.files)) {
+            Verify.notTrue(fileSize > Verify.Upload.maxSizeFile, "文件大小不超过" + Verify.Upload.maxSizeFileDesc);
+        } else if (StrUtil.equalsAny(fileSuffix, Verify.Upload.videos)) {
+            Verify.notTrue(fileSize > Verify.Upload.maxSizeVideo, "文件大小不超过" + Verify.Upload.maxSizeVideoDesc);
+        } else {
+            return null;
+        }
+        String fileName = StrUtil.format("{}/{}{}", DateUtil.format(DateUtil.date(), DateInPath), IdWorker.getIdStr(), fileSuffix);
+        log.info("上传文件,新文件名:{}", fileName);
+        return fileName;
+    }
+}

+ 30 - 0
upload/src/main/java/com/controller/common/CustomCORSConfiguration.java

@@ -0,0 +1,30 @@
+package com.controller.common;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+
+/**
+ * 跨域配置
+ */
+@Configuration
+public class CustomCORSConfiguration {
+    private CorsConfiguration buildConfig() {
+        CorsConfiguration corsConfiguration = new CorsConfiguration();
+        corsConfiguration.addAllowedHeader("*"); // 允许任何的head头部
+        corsConfiguration.addAllowedOrigin("*"); // 允许任何域名使用
+        corsConfiguration.addAllowedMethod("*"); // 允许任何的请求方法
+        corsConfiguration.setAllowCredentials(true);
+        return corsConfiguration;
+    }
+
+    // 添加CorsFilter拦截器,对任意的请求使用
+    @Bean
+    public CorsFilter corsFilter() {
+        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+        source.registerCorsConfiguration("/**", buildConfig());
+        return new CorsFilter(source);
+    }
+}

+ 23 - 0
upload/src/main/java/com/controller/common/ExceptionInfo.java

@@ -0,0 +1,23 @@
+package com.controller.common;
+
+import org.springframework.http.HttpStatus;
+
+public interface ExceptionInfo {
+    String RES_OK = String.valueOf(HttpStatus.OK.value());
+    String RES_ERROR = String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value());
+    String RES_NOT_FOUND = String.valueOf(HttpStatus.NOT_FOUND.value());
+    String RES_FORBIDDEN = String.valueOf(HttpStatus.FORBIDDEN.value());
+    String RES_BAD_REQUEST = String.valueOf(HttpStatus.BAD_REQUEST.value());
+    String RES_METHOD_NOT_ALLOWED = String.valueOf(HttpStatus.METHOD_NOT_ALLOWED.value());
+    String RES_UNAUTHORIZED = String.valueOf(HttpStatus.UNAUTHORIZED.value());
+    String MESSAGE_OK = "SUCCESS";
+    String MESSSGE_ERROR = "SYSTEM ERROR";
+
+    default String getStatusCode() {
+        return RES_OK;
+    }
+
+    default String getMessage() {
+        return "SUCCESS";
+    }
+}

+ 66 - 0
upload/src/main/java/com/controller/common/RestResponse.java

@@ -0,0 +1,66 @@
+package com.controller.common;
+
+
+public final class RestResponse<T> implements ExceptionInfo {
+    private final T data;
+    private final String statusCode;
+    private final String message;
+
+    private RestResponse(T data, String statusCode, String message) {
+        this.data = data;
+        this.statusCode = statusCode;
+        this.message = message;
+    }
+
+    public static <T> RestResponse<T> success(final T data, String statusCode, String message) {
+        return new RestResponse(data, statusCode, message);
+    }
+
+    public static <T> RestResponse<T> success(final T data, String message) {
+        return success(data, "1", message);
+    }
+
+    public static <T> RestResponse<T> success(final T data) {
+        return success(data, "1", "操作成功");
+    }
+
+    public static <T> RestResponse<T> success() {
+        return success(null, "9", "暂无数据");
+    }
+
+    public static <T> RestResponse<T> fail(String statusCode, String message) {
+        return new RestResponse((Object) null, statusCode, message);
+    }
+
+    public static <T> RestResponse<T> fail(String message) {
+        return fail("0", message);
+    }
+
+    public static RestResponse fail() {
+        return success("0", "操作失败");
+    }
+
+    public static <T> RestResponse<T> failParam() {
+        return fail("0", "缺少参数或参数有误");
+    }
+
+    public static <T> RestResponse<T> exception() {
+        return fail("-1", "操作发生异常");
+    }
+
+    public static <T> RestResponse<T> exception(String message) {
+        return fail("-1", message);
+    }
+
+    public T getData() {
+        return this.data;
+    }
+
+    public String getStatusCode() {
+        return this.statusCode;
+    }
+
+    public String getMessage() {
+        return this.message;
+    }
+}

+ 71 - 0
upload/src/main/java/com/controller/common/SystemConfiguration.java

@@ -0,0 +1,71 @@
+package com.controller.common;
+
+import cn.com.ty.lift.common.aliservice.aliyunoss.AliyunOSS;
+import cn.com.ty.lift.common.verify.Verifier;
+import cn.hutool.core.util.StrUtil;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.aop.support.DefaultPointcutAdvisor;
+import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * <p>
+ * 配置bean注入
+ * </p>
+ *
+ * @author wcz
+ * @since 2019/12/3
+ */
+@Slf4j
+@Data
+@Configuration
+@ConfigurationProperties(prefix = "aliyun.oss")
+public class SystemConfiguration {
+
+    private String endpoint;
+
+    private String bucketName;
+
+    private String accessKeySecret;
+
+    private String accessKeyId;
+
+    @PostConstruct
+    private void print() {
+        log.info("Hint: the Configuration for Aliyun OSS Client.");
+        log.info("============================================================");
+        log.info("###| endpoint       : {}", endpoint);
+        log.info("###| accessKeyId    : {}", accessKeyId);
+        log.info("###| accessKeySecret: {}", accessKeySecret);
+        log.info("###| bucketName     : {}", bucketName);
+        log.info("============================================================");
+    }
+
+    /**
+     * 创建aliyun OSS bean,每次使用完连接释放
+     */
+    public AliyunOSS build() {
+        if (StrUtil.hasEmpty(endpoint, accessKeyId, accessKeySecret, bucketName)) {
+            return AliyunOSS.me();
+        }
+        return AliyunOSS.me(endpoint, accessKeyId, accessKeySecret, bucketName);
+    }
+
+    /**
+     * 方法参数校验拦截器,标注了@Verifier的方法,会检查参数,如果参数不满足条件,直接抛出异常
+     */
+    @Bean
+    public DefaultPointcutAdvisor defaultPointcutAdvisor() {
+        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
+        advisor.setPointcut(new AnnotationMatchingPointcut(RestController.class, Verifier.class));
+        advisor.setAdvice(new VerifyMethodInterceptor());
+        advisor.setOrder(2);
+        return advisor;
+    }
+}

+ 45 - 0
upload/src/main/java/com/controller/common/VerifyMethodInterceptor.java

@@ -0,0 +1,45 @@
+package com.controller.common;
+
+import cn.com.ty.lift.common.verify.Ver;
+import cn.com.ty.lift.common.verify.Verifier;
+import cn.com.ty.lift.common.verify.VerifyProcessor;
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+
+/**
+ * the {@link MethodInterceptor} for verify parameter.
+ */
+public class VerifyMethodInterceptor implements MethodInterceptor {
+    @Override
+    public Object invoke(MethodInvocation invocation) throws Throwable {
+        //check whether the method is present with verifier annotation.
+        Method method = invocation.getMethod();
+        boolean annotationPresent = method.isAnnotationPresent(Verifier.class);
+        if (!annotationPresent) {
+            return invocation.proceed();
+        }
+        //check the list of parameters.
+        Parameter[] parameters = method.getParameters();
+        if (null == parameters || parameters.length == 0) {
+            return invocation.proceed();
+        }
+        //if the parameter is present with Ver. return the index.
+        Object object = null;
+        Object[] arguments = invocation.getArguments();
+        for (int i = 0; i < parameters.length; i++) {
+            if (parameters[i].isAnnotationPresent(Ver.class)) {
+                object = arguments[i];
+                break;
+            }
+        }
+        if (null == object) {
+            return invocation.proceed();
+        }
+        Verifier verifier = method.getDeclaredAnnotation(Verifier.class);
+        VerifyProcessor.perform(object, verifier.fields());
+        return invocation.proceed();
+    }
+}

+ 7 - 0
upload/src/main/resources/application-prod.yml

@@ -0,0 +1,7 @@
+#aliyun OSS服务配置信息,加载到SystemConfiguration
+aliyun:
+  oss:
+    endpoint: http://oss-cn-beijing.aliyuncs.com
+    bucketName: temp15827479607
+    accessKeyId: LTAI4FkSqFZa6LH9HqAsVott
+    accessKeySecret: w7GXuh5tf1hduQuZ2AzT3a4q14BI1i

+ 12 - 0
upload/src/main/resources/application.yml

@@ -0,0 +1,12 @@
+server:
+  port: 20234
+
+spring:
+  application:
+    name: lift-upload-service
+  profiles:
+    active: prod
+  servlet:
+    multipart:
+      max-file-size: 512MB  # Max file size,默认1M
+      max-request-size: 512MB  # Max request size,默认10M

+ 144 - 0
upload/src/main/resources/logback-spring.xml

@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--debug="true" : 打印 logback 内部状态(默认当 logback 运行出错时才会打印内部状态 ), 配置该属性后打印条件如下(同时满足):
+    1、找到配置文件
+    2、配置文件是一个格式正确的xml文件 也可编程实现打印内部状态,
+    例如: LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory(); StatusPrinter.print(lc); -->
+<!-- scan="true" : 自动扫描该配置文件,若有修改则重新加载该配置文件 -->
+<!-- scanPeriod="30 seconds" : 配置自动扫面时间间隔
+    (单位可以是:milliseconds, seconds, minutes or hours,默认为:milliseconds),
+    默认为1分钟,scan="true"时该配置才会生效 -->
+        <!--https://raw.githubusercontent.com/enricopulatzo/logback-XSD/master/src/main/xsd/logback.xsd-->
+<configuration
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/enricopulatzo/logback-XSD/master/src/main/xsd/logback.xsd"
+        debug="false" scan="true" scanPeriod="30 seconds">
+
+    <property name="PROJECT" value="lift-upload"/>
+    <property name="ROOT" value="logs/${PROJECT}/"/>
+    <property name="FILE_SIZE" value="10MB"/>
+    <property name="MAX_HISTORY" value="100"/>
+    <timestamp key="DATETIME" datePattern="yyyy-MM-dd HH:mm"/>
+
+    <property name="PATTERN" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss} [%thread] %logger{30} - %m%n" />
+    <!-- 控制台打印 -->
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <!--是否支持ANSI color codes(类似linux中的shell脚本的输出字符串颜色控制代码)。默认为false。如果设置为true。例如:[31m 代表将前景色设置成红色。-->
+        <!--在windows中,需要提供"org.fusesource.jansi:jansi:1.9",而在linux,mac os x中默认支持。-->
+        <!--<withJansi>true</withJansi>-->
+        <encoder charset="utf-8">
+            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
+            <!--"%black", "%red", "%green","%yellow","%blue", "%magenta","%cyan", "%white", "%gray", "%boldRed","%boldGreen", -->
+            <!--"%boldYellow", "%boldBlue", "%boldMagenta""%boldCyan", "%boldWhite" and "%highlight"-->
+            <pattern>%highlight([%-5level]) %highlight(%d{yyyy-MM-dd HH:mm:ss}) %cyan([%thread]) %boldMagenta(%logger{30}) - %m%n
+            </pattern>
+        </encoder>
+    </appender>
+    <!-- ERROR 输入到文件,按日期和文件大小 -->
+    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <encoder charset="utf-8">
+            <pattern>${PATTERN}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>ERROR</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${ROOT}%d/error.%i.log</fileNamePattern>
+            <maxHistory>${MAX_HISTORY}</maxHistory>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>${FILE_SIZE}</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+        </rollingPolicy>
+    </appender>
+
+    <!-- WARN 输入到文件,按日期和文件大小 -->
+    <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <encoder charset="utf-8">
+            <pattern>${PATTERN}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>WARN</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${ROOT}%d/warn.%i.log</fileNamePattern>
+            <maxHistory>${MAX_HISTORY}</maxHistory>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>${FILE_SIZE}</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+        </rollingPolicy>
+    </appender>
+
+    <!-- INFO 输入到文件,按日期和文件大小 -->
+    <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <encoder charset="utf-8">
+            <pattern>${PATTERN}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>INFO</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${ROOT}%d/info.%i.log</fileNamePattern>
+            <maxHistory>${MAX_HISTORY}</maxHistory>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>${FILE_SIZE}</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+        </rollingPolicy>
+    </appender>
+    <!-- DEBUG 输入到文件,按日期和文件大小 -->
+    <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <encoder charset="utf-8">
+            <pattern>${PATTERN}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>DEBUG</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${ROOT}%d/debug.%i.log</fileNamePattern>
+            <maxHistory>${MAX_HISTORY}</maxHistory>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>${FILE_SIZE}</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+        </rollingPolicy>
+    </appender>
+    <!-- TRACE 输入到文件,按日期和文件大小 -->
+    <appender name="TRACE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <encoder charset="utf-8">
+            <pattern>${PATTERN}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>TRACE</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+        <rollingPolicy
+                class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${ROOT}%d/trace.%i.log</fileNamePattern>
+            <maxHistory>${MAX_HISTORY}</maxHistory>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>${FILE_SIZE}</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+        </rollingPolicy>
+    </appender>
+
+    <!-- SQL相关日志输出-->
+    <logger name="org.apache.ibatis" level="INFO" additivity="true"/>
+    <logger name="org.mybatis.spring" level="INFO" additivity="false"/>
+    <logger name="com.github.miemiedev.mybatis.paginator" level="INFO" additivity="false"/>
+
+    <!-- Logger 根目录 -->
+    <root level="ERROR">
+        <appender-ref ref="STDOUT"/>
+        <appender-ref ref="DEBUG"/>
+        <appender-ref ref="ERROR"/>
+        <appender-ref ref="WARN"/>
+        <appender-ref ref="INFO"/>
+        <appender-ref ref="TRACE"/>
+    </root>
+</configuration>