Преглед изворни кода

Merge branch 'develop' of http://132.232.206.88:3000/lift-manager/lift-server into feature-wcz

wcz пре 5 година
родитељ
комит
c024eb6286
20 измењених фајлова са 679 додато и 182 уклоњено
  1. 34 38
      lift-enterprise-service/src/main/java/cn/com/ty/lift/enterprise/option/controller/MaintenanceOptionController.java
  2. 4 3
      lift-enterprise-service/src/main/java/cn/com/ty/lift/enterprise/option/dao/entity/MaintenanceOption.java
  3. 0 13
      lift-enterprise-service/src/main/java/cn/com/ty/lift/enterprise/option/service/impl/MaintenanceOptionServiceImpl.java
  4. 1 1
      lift-enterprise-service/src/main/java/cn/com/ty/lift/enterprise/organization/service/OrganizationService.java
  5. 13 9
      lift-quan-service/src/main/java/cn/com/ty/lift/quan/news/controller/QuanNewsController.java
  6. 23 0
      lift-quan-service/src/main/java/cn/com/ty/lift/quan/news/dao/entity/QuanNews.java
  7. 0 6
      lift-quan-service/src/main/java/cn/com/ty/lift/quan/news/dao/entity/model/QuanNewsReq.java
  8. 35 112
      lift-quan-service/src/main/java/cn/com/ty/lift/quan/news/service/impl/QuanNewsServiceImpl.java
  9. 1 0
      pom.xml
  10. 43 0
      upload/pom.xml
  11. 11 0
      upload/src/main/java/com/Application.java
  12. 116 0
      upload/src/main/java/com/controller/common/CommonController.java
  13. 30 0
      upload/src/main/java/com/controller/common/CustomCORSConfiguration.java
  14. 23 0
      upload/src/main/java/com/controller/common/ExceptionInfo.java
  15. 66 0
      upload/src/main/java/com/controller/common/RestResponse.java
  16. 71 0
      upload/src/main/java/com/controller/common/SystemConfiguration.java
  17. 45 0
      upload/src/main/java/com/controller/common/VerifyMethodInterceptor.java
  18. 7 0
      upload/src/main/resources/application-prod.yml
  19. 12 0
      upload/src/main/resources/application.yml
  20. 144 0
      upload/src/main/resources/logback-spring.xml

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

@@ -32,21 +32,20 @@ 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) {
         IPage<MaintenanceOption> page = optionService.page(
                 new Page<>(req.getPageNum(), req.getPageSize()), new QueryWrapper<MaintenanceOption>()
-                        //0L是固定数据的公司id
-                        .in("mt_company_id", 0L, req.getMtCompanyId())
+                        //10086L是固定数据的公司id
+                        .in("mt_company_id", 10086L, req.getMtCompanyId())
                         .in(req.getType() != null, "type", type(req))
-                        .eq(req.getLiftType() != null, "lift_type", req.getLiftType())
-                        .orderByDesc("mt_company_id")
-        );
+                        .eq(req.getLiftCategory() != null, "lift_category", req.getLiftCategory())
+                        .eq(req.getStatus() != null, "status", req.getStatus()));
         if (page.getRecords().isEmpty()) {
             return RestResponse.success();
         }
@@ -61,19 +60,23 @@ public class MaintenanceOptionController {
      */
     @PostMapping("/options")
     public RestResponse options(@RequestBody OptionReq req) {
-        Integer liftType = req.getLiftType();
+        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>()
-                        //0L是固定数据的公司id
-                        .in("mt_company_id", 0L, req.getMtCompanyId())
+                        //10086L是固定数据的公司id
+                        .in("mt_company_id", 10086L, req.getMtCompanyId())
                         .in(req.getType() != null, "type", type(req))
-                        .eq(req.getLiftType() != null, "lift_type", req.getLiftType())
-                        .in(sort != null, "sort", sort)
-        );
+                        .eq(req.getLiftCategory() != null, "lift_category", req.getLiftCategory())
+                        .eq(req.getStatus() != null, "status", req.getStatus())
+                        .in(sort != null, "sort", sort));
         if (options.isEmpty()) {
             return RestResponse.success();
         }
@@ -81,53 +84,46 @@ public class MaintenanceOptionController {
     }
 
     /**
+     * 新增维保项
+     *
      * @param option 维保项信息
      * @return RestResponse
-     * @description 新增维保项
-     * @date 2019/12/19 9:20
      */
     @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) {
-        //0L是固定数据的公司id
-        if (option.getMtCompanyId().equals(0L)) {
-            return RestResponse.fail("默认维保项无法编辑");
-        }
-        if (optionService.updateById(option)) {
-            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.updateById(option));
         }
-        return RestResponse.failParam();
+        return RestResponse.fail("默认维保项无法编辑");
     }
 
     /**
+     * 判断是否是默认维保项,不是默认的维保项才可以删除
+     *
      * @param option 维保项id
      * @return RestResponse
-     * @description 判断是否是默认维保项,不是默认的维保项才可以删除
-     * @date 2019/12/19 9:20
      */
     @PostMapping("/delete")
     public RestResponse delete(@RequestBody MaintenanceOption option) {
-        //10086是平台的团队id
-        if (option.getMtCompanyId().equals(0L)) {
-            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("默认维保项无法删除");
     }
 
     /**

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

@@ -55,10 +55,11 @@ public class MaintenanceOption implements Serializable {
     private Integer type;
 
     /**
-     * 电梯类型  '(1乘客梯/载货电梯 2液压梯 3扶梯/人行道 4杂物梯)'
+     * 电梯类别(1:曳引梯;2:液压梯;3:杂物梯;4:自动扶梯;5:自动人行道)
+     * 电梯类型(1乘客梯/载货电梯 2液压梯 3扶梯/人行道 4杂物梯)
      */
-    @TableField("lift_type")
-    private Integer liftType;
+    @TableField("lift_category")
+    private Integer liftCategory;
 
     /**
      * 分类(1机房 2轿顶 3轿厢 4层门 5底坑井道)

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

+ 1 - 1
lift-enterprise-service/src/main/java/cn/com/ty/lift/enterprise/organization/service/OrganizationService.java

@@ -75,7 +75,7 @@ public class OrganizationService {
                 .isNotNull("province")
                 .isNotNull("city")
                 .isNotNull("district")
-                .isNotNull("unm")
+                .isNotNull("num")
                 .isNotNull("region_id")
                 .eq("mt_company_id", mtCompanyId)
         );

+ 13 - 9
lift-quan-service/src/main/java/cn/com/ty/lift/quan/news/controller/QuanNewsController.java

@@ -4,8 +4,6 @@ import cn.com.ty.lift.quan.news.dao.entity.QuanNews;
 import cn.com.ty.lift.quan.news.dao.entity.model.QuanNewsReq;
 import cn.com.ty.lift.quan.news.service.impl.QuanNewsServiceImpl;
 import cn.com.xwy.boot.web.dto.RestResponse;
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.AllArgsConstructor;
 import org.springframework.web.bind.annotation.*;
 
@@ -46,16 +44,16 @@ public class QuanNewsController {
         return quanNewsService.news(quanNews);
     }
 
+
     /**
-     * 根据id获取新闻
+     * 获取新闻
      *
-     * @param quanNews [新闻id]
-     * @return cn.com.xwy.boot.web.dto.RestResponse
-     * @since 2019/12/2 15:48
+     * @param quanNews 新闻id,用户id
+     * @return 新闻信息
      */
     @PostMapping
-    public RestResponse news(@RequestBody QuanNewsReq quanNews) {
-        return quanNewsService.getQuanNews(quanNews);
+    public RestResponse News(@RequestBody QuanNewsReq quanNews) {
+        return quanNewsService.getNews(quanNews);
     }
 
     /**
@@ -67,6 +65,9 @@ public class QuanNewsController {
      */
     @PostMapping("/add")
     public RestResponse add(@RequestBody QuanNews quanNews) {
+        if (!quanNews.getIsTop()) {
+            quanNews.setTopSerial(0);
+        }
         return RestResponse.success(quanNewsService.save(quanNews));
     }
 
@@ -77,8 +78,11 @@ public class QuanNewsController {
      * @return org.springframework.http.ResponseEntity
      * @since 2019/12/2 15:49
      */
-    @PostMapping("/update")
+    @PostMapping("/modify")
     public RestResponse updateNews(@RequestBody QuanNews quanNews) {
+        if (!quanNews.getIsTop()) {
+            quanNews.setTopSerial(0);
+        }
         return RestResponse.success(quanNewsService.updateById(quanNews));
     }
 

+ 23 - 0
lift-quan-service/src/main/java/cn/com/ty/lift/quan/news/dao/entity/QuanNews.java

@@ -31,6 +31,12 @@ public class QuanNews implements Serializable {
     @TableId(value = "id", type = IdType.ID_WORKER)
     private Long id;
 
+    /**
+     * 是否置顶
+     */
+    @TableField("is_top")
+    private Boolean isTop;
+
     /**
      * 置顶排序 0不置顶 非0就是置顶(按照数字大小排序)
      */
@@ -73,4 +79,21 @@ public class QuanNews implements Serializable {
     @TableField("release_id")
     private Long releaseId;
 
+    /**
+     * 浏览次数
+     */
+    @TableField(exist = false)
+    private Long lookNum;
+
+    /**
+     * 喜爱次数
+     */
+    @TableField(exist = false)
+    private Long likeNum;
+
+    /**
+     * 是否喜爱
+     */
+    @TableField(exist = false)
+    private Boolean isLike;
 }

+ 0 - 6
lift-quan-service/src/main/java/cn/com/ty/lift/quan/news/dao/entity/model/QuanNewsReq.java

@@ -44,10 +44,4 @@ public class QuanNewsReq extends QuanNews {
      * 点赞的用户id
      */
     private Long userId;
-
-    /**
-     * 新增时标识是否为置顶新闻
-     */
-    private Integer isTop;
-
 }

+ 35 - 112
lift-quan-service/src/main/java/cn/com/ty/lift/quan/news/service/impl/QuanNewsServiceImpl.java

@@ -8,6 +8,7 @@ import cn.com.ty.lift.quan.news.service.QuanNewsService;
 import cn.com.xwy.boot.web.dto.RestResponse;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fasterxml.jackson.databind.DeserializationFeature;
@@ -44,8 +45,7 @@ public class QuanNewsServiceImpl extends ServiceImpl<QuanNewsMapper, QuanNews> i
      */
     public RestResponse appNews(QuanNewsReq request) {
         Page<QuanNews> page = new Page<>(request.getPageNum(), request.getPageSize());
-        IPage<Map<String, Object>> news = this.pageMaps(page, new QueryWrapper<QuanNews>()
-                .select("id", "title", "content", "top_serial topSerial", "video_url videoUrl", "release_id releaseId", "release_user releaseUser", "release_date releaseDate")
+        IPage<QuanNews> news = this.page(page, Wrappers.<QuanNews>query()
                 .like(null != request.getTitle(), "title", request.getTitle())
                 .eq("top_serial", "0")
                 .orderByDesc("release_date"));
@@ -57,8 +57,7 @@ public class QuanNewsServiceImpl extends ServiceImpl<QuanNewsMapper, QuanNews> i
         newsAddLookAndLike(news.getRecords(), lookTimes, likeUsers);
         result.put("news", news);
         if (request.getHaveTops() == 1) {
-            List<Map<String, Object>> topNews = this.listMaps(new QueryWrapper<QuanNews>()
-                    .select("id", "title", "content", "top_serial topSerial", "video_url videoUrl", "release_id releaseId", "release_user releaseUser", "release_date releaseDate")
+            List<QuanNews> topNews = this.list(Wrappers.<QuanNews>query()
                     .ne("top_serial", "0")
                     .orderByAsc("top_serial"));
             //把点赞的用户数量和浏览量整入新闻字段中
@@ -70,8 +69,9 @@ public class QuanNewsServiceImpl extends ServiceImpl<QuanNewsMapper, QuanNews> i
 
     public RestResponse news(QuanNewsReq request) {
         Page<QuanNews> page = new Page<>(request.getPageNum(), request.getPageSize());
-        IPage<Map<String, Object>> news = this.pageMaps(page, new QueryWrapper<QuanNews>()
-                .select("id", "title", "content", "top_serial topSerial", "video_url videoUrl", "release_id releaseId", "release_user releaseUser", "release_date releaseDate")
+        IPage<QuanNews> news = this.page(page, Wrappers.<QuanNews>query()
+                .orderByDesc("is_top")
+                .orderByAsc("top_serial")
                 .orderByDesc("release_date"));
         //全部新闻的浏览量列表
         Map<Object, Object> lookTimes = redisTemplate.boundHashOps("system-quanNews-look-time").entries();
@@ -81,123 +81,44 @@ public class QuanNewsServiceImpl extends ServiceImpl<QuanNewsMapper, QuanNews> i
         return RestResponse.success(news);
     }
 
-    /**
-     * 将新闻置顶
-     *
-     * @since 2019/12/3 11:23
-     */
-    public RestResponse top(Long id, Integer type) {
-        QuanNews byId = this.getById(id);
-        if (byId == null) {
-            return RestResponse.success();
-        }
-        //1置顶 0取消置顶
-        if (type == 1) {
-            if (byId.getTopSerial() != 0) {
-                //如果新闻在置顶新闻中
-                Integer serial = byId.getTopSerial();
-
-                List<QuanNews> tops = this.list(new QueryWrapper<QuanNews>().ne("top_serial", 0));
-                for (QuanNews top : tops) {
-                    if (top.getTopSerial() < serial) {
-                        top.setTopSerial(top.getTopSerial() + 1);
-                    }
-                }
-                byId.setTopSerial(1);
-                //更新排序
-                this.updateBatchById(tops);
-                this.updateById(byId);
-            } else {
-                //如果新闻不是置顶新闻
-                //获取置顶新闻
-                List<QuanNews> news = this.list(new QueryWrapper<QuanNews>().select("id", "top_serial").ne("top_serial", 0));
-                if (!news.isEmpty()) {
-                    //如果有置顶新闻
-                    news.forEach(n -> {
-                        n.setTopSerial(n.getTopSerial() + 1);
-                    });
-                    this.updateBatchById(news, 100);
-                }
-                byId.setTopSerial(1);
-                //更新置顶新闻列表,新闻
-                if (this.updateById(byId)) {
-                    return RestResponse.success(null, "置顶成功");
-                } else {
-                    return RestResponse.fail();
-                }
-            }
-            return RestResponse.success(null, "置顶成功");
-        }
-        //1置顶 0取消置顶
-        if (type == 0) {
-            if (byId.getTopSerial() == 0) {
-                //如果不是置顶新闻
-                return RestResponse.success(null, "不是置顶新闻");
-            }
-            List<QuanNews> tops = this.list(new QueryWrapper<QuanNews>().select("id", "top_serial").ne("top_serial", 0).ne("id", id));
-            //如果置顶新闻为0个
-            if (tops.isEmpty()) {
-                byId.setTopSerial(0);
-                if (this.updateById(byId)) {
-                    return RestResponse.success(null, "取消置顶成功");
-                } else {
-                    return RestResponse.fail();
-                }
-            }
-            //比这个新闻排序大的都 序号-1
-            tops.forEach(top -> {
-                if (top.getTopSerial() > byId.getTopSerial()) {
-                    top.setTopSerial(top.getTopSerial() - 1);
-                }
-            });
-            byId.setTopSerial(0);
-            if (this.updateById(byId) && this.updateBatchById(tops)) {
-                return RestResponse.success(null, "取消置顶成功");
-            } else {
-                return RestResponse.fail();
-            }
-        }
-        return RestResponse.failParam();
-    }
-
     //把点赞的用户数量和浏览量整入新闻字段中
-    void newsAddLookAndLike(List<Map<String, Object>> records, Map<Object, Object> lookTimes, Map<Object, Object> likeUsers) {
-        for (Map<String, Object> record : records) {
-            Object id = record.get("id");
+    void newsAddLookAndLike(List<QuanNews> records, Map<Object, Object> lookTimes, Map<Object, Object> likeUsers) {
+        for (QuanNews quanNews : records) {
+            Long id = quanNews.getId();
             //如果没有浏览量
             if (lookTimes.isEmpty()) {
-                record.put("lookNum", 0);
+                quanNews.setLookNum(0L);
             } else {
                 //遍历lookTimes,查看对应id的新闻浏览量
                 for (Map.Entry<Object, Object> entry : lookTimes.entrySet()) {
                     Object key = entry.getKey();
-                    Object value = entry.getValue();
+                    Long value = Long.valueOf((Integer) entry.getValue());
                     if (key.equals(id.toString())) {
-                        record.put("lookNum", value);
+                        quanNews.setLookNum(value);
                         break;
                     }
-                    record.put("lookNum", 0);
+                    quanNews.setLookNum(0L);
                 }
             }
             //如果没有用户喜爱
             if (likeUsers.isEmpty()) {
-                record.put("likeNum", 0);
+                quanNews.setLikeNum(0L);
             } else {
                 //遍历likeUsers,查看对应id的新闻的点赞量
                 for (Map.Entry<Object, Object> entry : likeUsers.entrySet()) {
                     String k = entry.getKey().toString();
                     ArrayList v = (ArrayList) entry.getValue();
                     if (k.equals(id.toString())) {
-                        record.put("likeNum", v.size());
+                        quanNews.setLikeNum((long) v.size());
                         break;
                     }
-                    record.put("likeNum", 0);
+                    quanNews.setLikeNum(0L);
                 }
             }
         }
     }
 
-
+    @SuppressWarnings({"unchecked", "rawtypes"})
     public RestResponse like(QuanNewsReq request) {
         String userId = request.getUserId().toString();
         String id = request.getId().toString();
@@ -222,24 +143,26 @@ public class QuanNewsServiceImpl extends ServiceImpl<QuanNewsMapper, QuanNews> i
     }
 
     //获取一条新闻
-    public RestResponse getQuanNews(QuanNewsReq request) {
-        Map<String, Object> byId = this.getMap(new QueryWrapper<QuanNews>().eq("id", request.getId()));
-        if (null != byId) {
-            String id = byId.get("id").toString();
-            Long lookNum = redisTemplate.boundHashOps("system-quanNews-look-time").increment(id, 1);
-            int isLike;
-            ArrayList users = (ArrayList) redisTemplate.opsForHash().get("system-quanNews-like-users", id);
-            if (users != null && users.contains(request.getUserId().toString())) {
-                isLike = 1;
-            } else {
-                isLike = 0;
-            }
-            byId.put("lookNum", lookNum);
-            byId.put("isLike", isLike);
-            return RestResponse.success(byId, "成功");
-        } else {
+    @SuppressWarnings("rawtypes")
+    public RestResponse getNews(QuanNewsReq quanNewsReq) {
+        QuanNews byId = this.getById(quanNewsReq);
+        if (null == byId) {
             return RestResponse.success();
         }
+        String id = byId.getId().toString();
+        Long lookNum = redisTemplate
+                .boundHashOps("system-quanNews-look-time").increment(id, 1);
+        ArrayList users = (ArrayList) redisTemplate
+                .opsForHash().get("system-quanNews-like-users", id);
+        Long userId = quanNewsReq.getUserId();
+        boolean isLike = false;
+        if (null != userId) {
+            isLike = users != null && users.contains(userId.toString());
+        }
+        byId.setLookNum(lookNum);
+        byId.setLikeNum(users != null ? users.size() : 0L);
+        byId.setIsLike(isLike);
+        return RestResponse.success(byId, "成功");
     }
 
     public RestResponse areas() {

+ 1 - 0
pom.xml

@@ -13,6 +13,7 @@
         <module>lift-quan-service</module>
         <module>lift-push</module>
         <module>lift-iot</module>
+        <module>upload</module>
     </modules>
 
     <parent>

+ 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>