Просмотр исходного кода

Merge branch 'dev' of ssh://10.10.100.21/source/smartschool-platform into dev

chenw 7 лет назад
Родитель
Сommit
da9663f710
56 измененных файлов с 1512 добавлено и 199 удалено
  1. 31 0
      applications/school/school-dto/src/main/java/com/usoftchina/smartschool/school/enums/NoticeTemplate.java
  2. 45 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/controller/SchoolTemplateController.java
  3. 15 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/SchoolTemplateService.java
  4. 73 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/SchoolTemplateServiceImpl.java
  5. 9 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/HomeWorkServiceImpl.java
  6. 12 2
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/NoticeServiceImpl.java
  7. 36 2
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/ScoreServiceImpl.java
  8. 1 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/exception/BizExceptionCode.java
  9. 25 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/SchoolTemplateMapper.java
  10. 55 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/po/SchoolTemplate.java
  11. 104 0
      applications/school/school-server/src/main/resources/mapper/SchoolTemplateMapper.xml
  12. 10 46
      base-servers/file/file-api/src/main/java/com/usoftchina/smartschool/file/api/util/ByteArrayMultipartFile.java
  13. 35 0
      base-servers/file/file-api/src/main/java/com/usoftchina/smartschool/file/api/util/FileUploadUtils.java
  14. 0 4
      base-servers/file/file-dto/pom.xml
  15. 17 4
      base-servers/file/file-dto/src/main/java/com/usoftchina/smartschool/file/dto/FileInfoDTO.java
  16. 41 0
      base-servers/file/file-server-fdfs/pom.xml
  17. 1 1
      base-servers/file/file-server-fdfs/src/main/docker/Dockerfile
  18. 5 8
      base-servers/file/file-server-fdfs/src/main/java/com/usoftchina/smartschool/file/fdfs/FdfsFileApplication.java
  19. 11 11
      base-servers/file/file-server-fdfs/src/main/resources/application.yml
  20. 1 4
      base-servers/file/file-server-fdfs/src/main/resources/config/application-docker-prod.yml
  21. 0 0
      base-servers/file/file-server-fdfs/src/main/resources/config/application-docker.yml
  22. 0 0
      base-servers/file/file-server-fdfs/src/main/resources/logback-spring.xml
  23. 41 0
      base-servers/file/file-server-qcloud/pom.xml
  24. 6 0
      base-servers/file/file-server-qcloud/src/main/docker/Dockerfile
  25. 26 0
      base-servers/file/file-server-qcloud/src/main/java/com/usoftchina/smartschool/file/qcloud/QCloudFileApplication.java
  26. 97 0
      base-servers/file/file-server-qcloud/src/main/resources/application.yml
  27. 29 0
      base-servers/file/file-server-qcloud/src/main/resources/config/application-docker-cloud.yml
  28. 7 0
      base-servers/file/file-server-qcloud/src/main/resources/config/application-docker-prod.yml
  29. 131 0
      base-servers/file/file-server-qcloud/src/main/resources/logback-spring.xml
  30. 2 19
      base-servers/file/file-server/pom.xml
  31. 6 25
      base-servers/file/file-server/src/main/java/com/usoftchina/smartschool/file/controller/FileController.java
  32. 31 29
      base-servers/file/file-server/src/main/java/com/usoftchina/smartschool/file/po/FileInfo.java
  33. 0 13
      base-servers/file/file-server/src/main/resources/config/application-dev.yml
  34. 0 12
      base-servers/file/file-server/src/main/resources/config/application-docker-dev.yml
  35. 0 12
      base-servers/file/file-server/src/main/resources/config/application-docker-test.yml
  36. 0 0
      base-servers/file/file-server/src/main/resources/i18n/messages_en_US.properties
  37. 0 0
      base-servers/file/file-server/src/main/resources/i18n/messages_zh_CN.properties
  38. 24 0
      base-servers/file/file-storage-fdfs/pom.xml
  39. 21 0
      base-servers/file/file-storage-fdfs/src/main/java/com/usoftchina/smartschool/file/storage/fdfs/FdfsConfig.java
  40. 50 0
      base-servers/file/file-storage-fdfs/src/main/java/com/usoftchina/smartschool/file/storage/fdfs/FdfsFileStorageClient.java
  41. 3 0
      base-servers/file/file-storage-fdfs/src/main/resources/META-INF/spring.factories
  42. 35 0
      base-servers/file/file-storage-qcloud/pom.xml
  43. 81 0
      base-servers/file/file-storage-qcloud/src/main/java/com/usoftchina/smartschool/file/storage/qcloud/COSFileStorageClient.java
  44. 58 0
      base-servers/file/file-storage-qcloud/src/main/java/com/usoftchina/smartschool/file/storage/qcloud/CosProperties.java
  45. 24 0
      base-servers/file/file-storage-qcloud/src/main/java/com/usoftchina/smartschool/file/storage/qcloud/QCloudConfig.java
  46. 3 0
      base-servers/file/file-storage-qcloud/src/main/resources/META-INF/spring.factories
  47. 37 0
      base-servers/file/file-storage-qcloud/src/test/java/com/usoftchina/smartschool/file/storage/qcloud/COSFileStorageClientTest.java
  48. 49 0
      base-servers/file/file-storage-qcloud/src/test/java/com/usoftchina/smartschool/file/storage/qcloud/RandomTextFile.java
  49. 15 0
      base-servers/file/file-storage/pom.xml
  50. 44 0
      base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/FileMetadata.java
  51. 39 0
      base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/FileStorageClient.java
  52. 1 1
      base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/util/FileType.java
  53. 3 6
      base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/util/FileTypeUtils.java
  54. 97 0
      base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/util/FilenameUtils.java
  55. 5 0
      base-servers/file/pom.xml
  56. 20 0
      pom.xml

+ 31 - 0
applications/school/school-dto/src/main/java/com/usoftchina/smartschool/school/enums/NoticeTemplate.java

@@ -0,0 +1,31 @@
+package com.usoftchina.smartschool.school.enums;
+
+public enum NoticeTemplate {
+
+    INOUT_NOTICE("inout", "出入校提醒"),
+    SCHOOL_NOTICE("school", "学校通知"),
+    HOMEWORK_NOTICE("homework", "作业通知"),
+    ASK4LEAVE_NOTICE("ask4leave", "学生请假申请"),
+    LEAVECONFIRM_NOTICE("leaveConfirm", "学生请假确认"),
+    SCORE_NOTICE("score", "成绩通知"),
+    UNAUDIT_NOTICE("unAudit", "待审批通知"),
+    MEETING_NOTICE("meeting", "会议提醒"),
+    MONEY_NOTICE("money", "资金异动提醒");
+
+    private String code;
+
+    private String title;
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    NoticeTemplate(String code, String title) {
+        this.code = code;
+        this.title = title;
+    }
+}

+ 45 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/controller/SchoolTemplateController.java

@@ -0,0 +1,45 @@
+package com.usoftchina.smartschool.school.basic.controller;
+
+import com.github.pagehelper.PageInfo;
+import com.usoftchina.smartschool.base.Result;
+import com.usoftchina.smartschool.page.PageDefault;
+import com.usoftchina.smartschool.page.PageRequest;
+import com.usoftchina.smartschool.school.basic.service.SchoolTemplateService;
+import com.usoftchina.smartschool.school.dto.DocBaseDTO;
+import com.usoftchina.smartschool.school.dto.ListReqDTO;
+import com.usoftchina.smartschool.school.po.SchoolTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 学校微信推送模板
+ * @author: guq
+ * @create: 2019-03-14 11:51
+ **/
+@RestController
+@RequestMapping("/template")
+public class SchoolTemplateController {
+
+
+    @Autowired
+    private SchoolTemplateService schoolTemplateService;
+
+    @GetMapping("/list")
+    public Result getList(@PageDefault PageRequest page, ListReqDTO listReqDTO) {
+        PageInfo<SchoolTemplate> data = schoolTemplateService.getListData(page, listReqDTO);
+        return Result.success(data);
+    }
+
+    @GetMapping("/read/{id}")
+    public Result getFormData(@PathVariable("id") Long id) {
+        SchoolTemplate data = schoolTemplateService.getFormData(id);
+        return Result.success(data);
+    }
+
+    @PostMapping("/save")
+    public Result saveFormData(@RequestBody SchoolTemplate data) {
+        DocBaseDTO baseDTO = schoolTemplateService.saveFormData(data);
+        return Result.success(baseDTO);
+    }
+
+}

+ 15 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/SchoolTemplateService.java

@@ -0,0 +1,15 @@
+package com.usoftchina.smartschool.school.basic.service;
+
+import com.github.pagehelper.PageInfo;
+import com.usoftchina.smartschool.page.PageRequest;
+import com.usoftchina.smartschool.school.dto.DocBaseDTO;
+import com.usoftchina.smartschool.school.dto.ListReqDTO;
+import com.usoftchina.smartschool.school.po.SchoolTemplate;
+
+public interface SchoolTemplateService {
+    PageInfo<SchoolTemplate> getListData(PageRequest page, ListReqDTO listReqDTO);
+
+    SchoolTemplate getFormData(Long id);
+
+    DocBaseDTO saveFormData(SchoolTemplate data);
+}

+ 73 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/SchoolTemplateServiceImpl.java

@@ -0,0 +1,73 @@
+package com.usoftchina.smartschool.school.basic.service.impl;
+
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.usoftchina.smartschool.context.BaseContextHolder;
+import com.usoftchina.smartschool.exception.BizException;
+import com.usoftchina.smartschool.page.PageRequest;
+import com.usoftchina.smartschool.school.basic.service.SchoolTemplateService;
+import com.usoftchina.smartschool.school.dto.DocBaseDTO;
+import com.usoftchina.smartschool.school.dto.ListReqDTO;
+import com.usoftchina.smartschool.school.exception.BizExceptionCode;
+import com.usoftchina.smartschool.school.mapper.SchoolTemplateMapper;
+import com.usoftchina.smartschool.school.po.SchoolTemplate;
+import com.usoftchina.smartschool.school.po.SysSchool;
+import com.usoftchina.smartschool.school.po.SysStudent;
+import com.usoftchina.smartschool.utils.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Calendar;
+import java.util.List;
+
+/**
+ * @author: guq
+ * @create: 2019-03-14 13:56
+ **/
+@Service
+public class SchoolTemplateServiceImpl implements SchoolTemplateService {
+
+
+    @Autowired
+    private SchoolTemplateMapper schoolTemplateMapper;
+
+    @Override
+    public PageInfo<SchoolTemplate> getListData(PageRequest page, ListReqDTO listReqDTO) {
+        PageHelper.startPage(page.getNumber(), page.getSize());
+        Long schoolId = BaseContextHolder.getSchoolId();
+        //condition语句
+        String condition = listReqDTO.getFinalCondition();
+        if(condition == null){
+            condition = "1=1";
+        }
+        List<SchoolTemplate> data = schoolTemplateMapper.selectByConditon(condition, schoolId);
+        PageInfo<SchoolTemplate> list = new PageInfo<>(data);
+        return list;
+    }
+
+    @Override
+    public SchoolTemplate getFormData(Long id) {
+        if (null == id || "0".equals(id)) {
+            throw new BizException(BizExceptionCode.USELESS_DATA);
+        }
+        SchoolTemplate data = schoolTemplateMapper.selectByPrimaryKey(id);
+        return data;
+    }
+
+    @Override
+    public DocBaseDTO saveFormData(SchoolTemplate formdata) {
+        if (StringUtils.isEmpty(formdata)){
+            throw new BizException(BizExceptionCode.EMPTY_DATA);
+        }
+        Long school_id = BaseContextHolder.getSchoolId();
+        formdata.setSt_schoolid(school_id);
+        //新增
+        if (StringUtils.isEmpty(formdata.getSt_id()) || "0".equals(formdata.getSt_id().toString())) {
+            schoolTemplateMapper.insertSelective(formdata);
+        } else {
+            //更新
+            schoolTemplateMapper.updateByPrimaryKeySelective(formdata);
+        }
+        return new DocBaseDTO(formdata.getSt_id());
+    }
+}

+ 9 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/HomeWorkServiceImpl.java

@@ -9,6 +9,7 @@ import com.usoftchina.smartschool.school.business.service.HomeWorkService;
 import com.usoftchina.smartschool.school.dto.BatchDealBaseDTO;
 import com.usoftchina.smartschool.school.dto.DocBaseDTO;
 import com.usoftchina.smartschool.school.dto.ListReqDTO;
+import com.usoftchina.smartschool.school.enums.NoticeTemplate;
 import com.usoftchina.smartschool.school.exception.BizExceptionCode;
 import com.usoftchina.smartschool.school.mapper.*;
 import com.usoftchina.smartschool.school.po.*;
@@ -46,6 +47,8 @@ public class HomeWorkServiceImpl implements HomeWorkService{
     private SysSchoolMapper sysSchoolMapper;
     @Autowired
     private WechatApi wechatApi;
+    @Autowired
+    private SchoolTemplateMapper schoolTemplateMapper;
 
     @Override
     public DocBaseDTO save(HomeWork formdata) {
@@ -132,6 +135,11 @@ public class HomeWorkServiceImpl implements HomeWorkService{
         SysSchool school = sysSchoolMapper.selectByPrimaryKey(BaseContextHolder.getSchoolId());
         //微信推送
         List<HomeworkNoticer> noticers = homeWorkMapper.selectHomeworkNoticer(id);
+        //模板信息
+        SchoolTemplate template = schoolTemplateMapper.selectByCode(NoticeTemplate.HOMEWORK_NOTICE.getCode(), school.getSchool_id());
+        if (StringUtils.isEmpty(template.getSt_templateid())) {
+            throw new BizException(BizExceptionCode.NULL_TEMPLATE);
+        }
         //消息内容
         List<MessageInfoDTO> msgs = new ArrayList<>();
         noticers.forEach(noticer -> {
@@ -143,6 +151,7 @@ public class HomeWorkServiceImpl implements HomeWorkService{
             msg.setTouser(noticer.getOpenid());
             msg.setAppId(school.getSchool_appid());
             msg.setSecret(school.getSchool_secret());
+            msg.setTemplateId(template.getSt_templateid());
             msgs.add(msg);
         });
         if (msgs.size() > 0) {

+ 12 - 2
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/NoticeServiceImpl.java

@@ -9,11 +9,14 @@ import com.usoftchina.smartschool.school.business.service.NoticeService;
 import com.usoftchina.smartschool.school.dto.BatchDealBaseDTO;
 import com.usoftchina.smartschool.school.dto.DocBaseDTO;
 import com.usoftchina.smartschool.school.dto.ListReqDTO;
+import com.usoftchina.smartschool.school.enums.NoticeTemplate;
 import com.usoftchina.smartschool.school.exception.BizExceptionCode;
 import com.usoftchina.smartschool.school.mapper.NoticeMapper;
+import com.usoftchina.smartschool.school.mapper.SchoolTemplateMapper;
 import com.usoftchina.smartschool.school.mapper.SysSchoolMapper;
 import com.usoftchina.smartschool.school.po.Notify;
 import com.usoftchina.smartschool.school.po.SchoolNoticer;
+import com.usoftchina.smartschool.school.po.SchoolTemplate;
 import com.usoftchina.smartschool.school.po.SysSchool;
 import com.usoftchina.smartschool.utils.DateUtils;
 import com.usoftchina.smartschool.utils.StringUtils;
@@ -43,7 +46,9 @@ public class NoticeServiceImpl implements NoticeService{
     @Autowired
     private WechatApi wechatApi;
 
-    final static String TEMPLATEID = "h0BkcnTo24b2jsficMeVO0B17GvE-VzlPvF0fVXea4w";
+    @Autowired
+    private SchoolTemplateMapper schoolTemplateMapper;
+
 
     @Override
     public DocBaseDTO save(Notify formdata) {
@@ -125,6 +130,11 @@ public class NoticeServiceImpl implements NoticeService{
         SysSchool school = sysSchoolMapper.selectByPrimaryKey(BaseContextHolder.getSchoolId());
         List<MessageInfoDTO> msgs = new ArrayList<>();
         List<SchoolNoticer> noticers = noticeMapper.selectNoticer(BaseContextHolder.getSchoolId());
+        //模板信息
+        SchoolTemplate template = schoolTemplateMapper.selectByCode(NoticeTemplate.HOMEWORK_NOTICE.getCode(), school.getSchool_id());
+        if (org.springframework.util.StringUtils.isEmpty(template.getSt_templateid())) {
+            throw new BizException(BizExceptionCode.NULL_TEMPLATE);
+        }
         noticers.forEach(noticer -> {
             MessageInfoDTO msg = new MessageInfoDTO();
             msg.setTitle(data.getNotify_title());
@@ -133,7 +143,7 @@ public class NoticeServiceImpl implements NoticeService{
             msg.setKeyword3(DateUtils.format());
             msg.setKeyword4(data.getNotify_details());
             msg.setRemark(data.getNotify_remarks());
-            msg.setTemplateId(TEMPLATEID);
+            msg.setTemplateId(template.getSt_templateid());
             msg.setTouser(noticer.getOpenid());
             msg.setAppId(school.getSchool_appid());
             msg.setSecret(school.getSchool_secret());

+ 36 - 2
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/ScoreServiceImpl.java

@@ -10,6 +10,7 @@ import com.usoftchina.smartschool.school.business.service.ScoreService;
 import com.usoftchina.smartschool.school.dto.BatchDealBaseDTO;
 import com.usoftchina.smartschool.school.dto.DocBaseDTO;
 import com.usoftchina.smartschool.school.dto.ListReqDTO;
+import com.usoftchina.smartschool.school.enums.NoticeTemplate;
 import com.usoftchina.smartschool.school.exception.BizExceptionCode;
 import com.usoftchina.smartschool.school.mapper.*;
 import com.usoftchina.smartschool.school.po.*;
@@ -57,8 +58,8 @@ public class ScoreServiceImpl implements ScoreService{
     @Autowired
     private WechatApi wechatApi;
 
-
-    final static String TEMPLATEID = "GwR7hZ9ya7ghAiH3PR-ws1l24P_ETE3phYJBjKTcpKY";
+    @Autowired
+    private SchoolTemplateMapper schoolTemplateMapper;
 
     @Autowired
     private SubjectMapper subjectMapper;
@@ -218,6 +219,8 @@ public class ScoreServiceImpl implements ScoreService{
         List<StuScore> appScores = new ArrayList<StuScore>();
         StuScore appScore = null;
         Long school_id = BaseContextHolder.getSchoolId();
+        //学校信息
+        SysSchool school = sysSchoolMapper.selectByPrimaryKey(BaseContextHolder.getSchoolId());
         ScoreImport main = scoreMapper.selectByPrimaryKey(id);
         List<ScoreImportdetail> details = scoreMapper.selectDetail(id);
         for (ScoreImportdetail detail : details) {
@@ -237,6 +240,37 @@ public class ScoreServiceImpl implements ScoreService{
             appScores.add(appScore);
         }
         scoreMapper.batchInsert(appScores);
+
+        //微信推送
+        List<ScoreNoticer> noticers = scoreMapper.selectWechatMsg(id);
+        //消息内容
+        List<MessageInfoDTO> msgs = new ArrayList<>();
+        //模板信息
+        SchoolTemplate template = schoolTemplateMapper.selectByCode(NoticeTemplate.HOMEWORK_NOTICE.getCode(), school.getSchool_id());
+        if (StringUtils.isEmpty(template.getSt_templateid())) {
+            throw new BizException(BizExceptionCode.NULL_TEMPLATE);
+        }
+        noticers.forEach(noticer -> {
+            MessageInfoDTO msg = new MessageInfoDTO();
+            msg.setTitle("您好,请查收您小孩" + noticer.getStuName() + "的成绩单");
+            msg.setKeyword1(noticer.getStuName());
+            msg.setKeyword2(noticer.getStuNo());
+            msg.setKeyword3(main.getSi_examtitle());
+            msg.setKeyword4(DateUtils.format(main.getSi_examdate(),"yyyy-MM-dd"));
+            msg.setKeyword5(school.getSchool_name());
+            msg.setRemark("成绩为:" + noticer.getScore());
+            msg.setTemplateId(template.getSt_templateid());
+            msg.setTouser(noticer.getOpenid());
+            msg.setAppId(school.getSchool_appid());
+            msg.setSecret(school.getSchool_secret());
+            msgs.add(msg);
+        });
+        if (msgs.size() > 0) {
+            TransferDTO transferDTO = new TransferDTO();
+            transferDTO.setData(msgs);
+            //调用推送接口
+            wechatApi.largeMessages(transferDTO);
+        }
         //更新已转标志
         scoreMapper.updateTurnPublish(id);
     }

+ 1 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/exception/BizExceptionCode.java

@@ -34,6 +34,7 @@ public enum BizExceptionCode implements BaseExceptionCode {
     NOTICE_RELEASE_STATUS(600007, "学校通知已生效,无法删除"),
     ILLEGAL_Gender(600007, "无效性别"),
     ILLEGAL_MARRIAGE(600008, "婚姻状态无效,应为:已婚或未婚"),
+    NULL_TEMPLATE(600010, "模板ID为空"),
     NOT_EXISTS_SUBJECT(60005, "科目<u>%s</u>不存在");
 
 

+ 25 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/SchoolTemplateMapper.java

@@ -0,0 +1,25 @@
+package com.usoftchina.smartschool.school.mapper;
+
+import com.usoftchina.smartschool.school.po.SchoolTemplate;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+@Mapper
+public interface SchoolTemplateMapper {
+    int deleteByPrimaryKey(Long st_id);
+
+    int insert(SchoolTemplate record);
+
+    int insertSelective(SchoolTemplate record);
+
+    SchoolTemplate selectByPrimaryKey(Long st_id);
+
+    int updateByPrimaryKeySelective(SchoolTemplate record);
+
+    int updateByPrimaryKey(SchoolTemplate record);
+
+    List<SchoolTemplate> selectByConditon(@Param("con") String condition, @Param("school_id") Long schoolId);
+
+    SchoolTemplate selectByCode(@Param("code") String code, @Param("school_id") Long school_id);
+}

+ 55 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/po/SchoolTemplate.java

@@ -0,0 +1,55 @@
+package com.usoftchina.smartschool.school.po;
+
+import java.io.Serializable;
+
+public class SchoolTemplate implements Serializable{
+    private Long st_id;
+
+    private String st_code;
+
+    private String st_name;
+
+    private String st_templateid;
+
+    private Long st_schoolid;
+
+    public Long getSt_id() {
+        return st_id;
+    }
+
+    public void setSt_id(Long st_id) {
+        this.st_id = st_id;
+    }
+
+    public String getSt_code() {
+        return st_code;
+    }
+
+    public void setSt_code(String st_code) {
+        this.st_code = st_code == null ? null : st_code.trim();
+    }
+
+    public String getSt_name() {
+        return st_name;
+    }
+
+    public void setSt_name(String st_name) {
+        this.st_name = st_name == null ? null : st_name.trim();
+    }
+
+    public String getSt_templateid() {
+        return st_templateid;
+    }
+
+    public void setSt_templateid(String st_templateid) {
+        this.st_templateid = st_templateid == null ? null : st_templateid.trim();
+    }
+
+    public Long getSt_schoolid() {
+        return st_schoolid;
+    }
+
+    public void setSt_schoolid(Long st_schoolid) {
+        this.st_schoolid = st_schoolid;
+    }
+}

+ 104 - 0
applications/school/school-server/src/main/resources/mapper/SchoolTemplateMapper.xml

@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.usoftchina.smartschool.school.mapper.SchoolTemplateMapper" >
+  <resultMap id="BaseResultMap" type="com.usoftchina.smartschool.school.po.SchoolTemplate" >
+    <id column="st_id" property="st_id" jdbcType="BIGINT" />
+    <result column="st_code" property="st_code" jdbcType="VARCHAR" />
+    <result column="st_name" property="st_name" jdbcType="VARCHAR" />
+    <result column="st_templateid" property="st_templateid" jdbcType="VARCHAR" />
+    <result column="st_schoolid" property="st_schoolid" jdbcType="BIGINT" />
+  </resultMap>
+  <sql id="Base_Column_List" >
+    st_id, st_code, st_name, st_templateid, st_schoolid
+  </sql>
+  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long" >
+    select 
+    <include refid="Base_Column_List" />
+    from school_template
+    where st_id = #{st_id,jdbcType=BIGINT}
+  </select>
+  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long" >
+    delete from school_template
+    where st_id = #{st_id,jdbcType=BIGINT}
+  </delete>
+  <insert id="insert" parameterType="com.usoftchina.smartschool.school.po.SchoolTemplate" >
+    insert into school_template (st_id, st_code, st_name, 
+      st_templateid, st_schoolid)
+    values (#{st_id,jdbcType=BIGINT}, #{st_code,jdbcType=VARCHAR}, #{st_name,jdbcType=VARCHAR}, 
+      #{st_templateid,jdbcType=VARCHAR}, #{st_schoolid,jdbcType=BIGINT})
+  </insert>
+  <insert id="insertSelective" parameterType="com.usoftchina.smartschool.school.po.SchoolTemplate" >
+    insert into school_template
+    <trim prefix="(" suffix=")" suffixOverrides="," >
+      <if test="st_code != null" >
+        st_code,
+      </if>
+      <if test="st_name != null" >
+        st_name,
+      </if>
+      <if test="st_templateid != null" >
+        st_templateid,
+      </if>
+      <if test="st_schoolid != null" >
+        st_schoolid,
+      </if>
+    </trim>
+    <trim prefix="values (" suffix=")" suffixOverrides="," >
+      <if test="st_code != null" >
+        #{st_code,jdbcType=VARCHAR},
+      </if>
+      <if test="st_name != null" >
+        #{st_name,jdbcType=VARCHAR},
+      </if>
+      <if test="st_templateid != null" >
+        #{st_templateid,jdbcType=VARCHAR},
+      </if>
+      <if test="st_schoolid != null" >
+        #{st_schoolid,jdbcType=BIGINT},
+      </if>
+    </trim>
+  </insert>
+  <update id="updateByPrimaryKeySelective" parameterType="com.usoftchina.smartschool.school.po.SchoolTemplate" >
+    update school_template
+    <set >
+      <if test="st_code != null" >
+        st_code = #{st_code,jdbcType=VARCHAR},
+      </if>
+      <if test="st_name != null" >
+        st_name = #{st_name,jdbcType=VARCHAR},
+      </if>
+      <if test="st_templateid != null" >
+        st_templateid = #{st_templateid,jdbcType=VARCHAR},
+      </if>
+      <if test="st_schoolid != null" >
+        st_schoolid = #{st_schoolid,jdbcType=BIGINT},
+      </if>
+    </set>
+    where st_id = #{st_id,jdbcType=BIGINT}
+  </update>
+  <update id="updateByPrimaryKey" parameterType="com.usoftchina.smartschool.school.po.SchoolTemplate" >
+    update school_template
+    set st_code = #{st_code,jdbcType=VARCHAR},
+      st_name = #{st_name,jdbcType=VARCHAR},
+      st_templateid = #{st_templateid,jdbcType=VARCHAR},
+      st_schoolid = #{st_schoolid,jdbcType=BIGINT}
+    where st_id = #{st_id,jdbcType=BIGINT}
+  </update>
+
+  <select id="selectByConditon" resultMap="BaseResultMap">
+    select * from school_template <where>
+    <if test="con != null">
+      ${con}
+    </if>
+    <if test="school_id != null">
+      and  st_schoolid = #{school_id}
+    </if>
+  </where>
+    order by st_id DESC
+  </select>
+
+  <select id="selectByCode" resultMap="BaseResultMap">
+    select * from school_template where st_code=#{code} and st_schoolid=#{school_id}
+  </select>
+
+</mapper>

+ 10 - 46
base-servers/file/file-dto/src/main/java/com/usoftchina/smartschool/file/dto/MyMultipartFile.java → base-servers/file/file-api/src/main/java/com/usoftchina/smartschool/file/api/util/ByteArrayMultipartFile.java

@@ -1,4 +1,4 @@
-package com.usoftchina.smartschool.file.dto;
+package com.usoftchina.smartschool.file.api.util;
 
 import org.springframework.lang.Nullable;
 import org.springframework.util.Assert;
@@ -11,11 +11,10 @@ import java.io.IOException;
 import java.io.InputStream;
 
 /**
- * @Author chenwei
- * @Date 2019-03-14
+ * @author yingp
+ * @date 2019/1/15
  */
-public class MyMultipartFile implements MultipartFile {
-
+public class ByteArrayMultipartFile implements MultipartFile {
     private final String name;
 
     private String originalFilename;
@@ -25,40 +24,16 @@ public class MyMultipartFile implements MultipartFile {
 
     private final byte[] content;
 
-
-    /**
-     * Create a new MockMultipartFile with the given content.
-     * @param name the name of the file
-     * @param content the content of the file
-     */
-    public MyMultipartFile(String name, @Nullable byte[] content) {
+    public ByteArrayMultipartFile(String name, byte[] content) throws IOException {
         this(name, "", null, content);
     }
 
-    public MyMultipartFile(String name, String originalName, @Nullable byte[] content) {
-        this(name, originalName, null, content);
-    }
-
-    /**
-     * Create a new MockMultipartFile with the given content.
-     * @param name the name of the file
-     * @param contentStream the content of the file as stream
-     * @throws IOException if reading from the stream failed
-     */
-    public MyMultipartFile(String name, InputStream contentStream) throws IOException {
-        this(name, "", null, FileCopyUtils.copyToByteArray(contentStream));
+    public ByteArrayMultipartFile(String name, String contentType, byte[] content) throws IOException {
+        this(name, "", contentType, content);
     }
 
-    /**
-     * Create a new MockMultipartFile with the given content.
-     * @param name the name of the file
-     * @param originalFilename the original filename (as on the client's machine)
-     * @param contentType the content type (if known)
-     * @param content the content of the file
-     */
-    public MyMultipartFile(
+    public ByteArrayMultipartFile(
             String name, @Nullable String originalFilename, @Nullable String contentType, @Nullable byte[] content) {
-
         Assert.hasLength(name, "Name must not be null");
         this.name = name;
         this.originalFilename = (originalFilename != null ? originalFilename : "");
@@ -66,22 +41,12 @@ public class MyMultipartFile implements MultipartFile {
         this.content = (content != null ? content : new byte[0]);
     }
 
-    /**
-     * Create a new MockMultipartFile with the given content.
-     * @param name the name of the file
-     * @param originalFilename the original filename (as on the client's machine)
-     * @param contentType the content type (if known)
-     * @param contentStream the content of the file as stream
-     * @throws IOException if reading from the stream failed
-     */
-    public MyMultipartFile(
+    public ByteArrayMultipartFile(
             String name, @Nullable String originalFilename, @Nullable String contentType, InputStream contentStream)
             throws IOException {
-
         this(name, originalFilename, contentType, FileCopyUtils.copyToByteArray(contentStream));
     }
 
-
     @Override
     public String getName() {
         return this.name;
@@ -100,7 +65,7 @@ public class MyMultipartFile implements MultipartFile {
 
     @Override
     public boolean isEmpty() {
-        return (this.content.length == 0);
+        return this.content.length == 0;
     }
 
     @Override
@@ -122,5 +87,4 @@ public class MyMultipartFile implements MultipartFile {
     public void transferTo(File dest) throws IOException, IllegalStateException {
         FileCopyUtils.copy(this.content, dest);
     }
-
 }

+ 35 - 0
base-servers/file/file-api/src/main/java/com/usoftchina/smartschool/file/api/util/FileUploadUtils.java

@@ -0,0 +1,35 @@
+package com.usoftchina.smartschool.file.api.util;
+
+import com.usoftchina.smartschool.base.Result;
+import com.usoftchina.smartschool.context.SpringContextHolder;
+import com.usoftchina.smartschool.exception.BizException;
+import com.usoftchina.smartschool.file.api.FileApi;
+import com.usoftchina.smartschool.file.dto.FileInfoDTO;
+
+/**
+ * @author yingp
+ * @date 2019/1/15
+ */
+public class FileUploadUtils {
+
+    /**
+     * 文件上传
+     *
+     * @param fileName
+     * @param contentType
+     * @param content
+     * @return
+     * @throws Exception
+     */
+    public static FileInfoDTO upload(String fileName, String contentType, byte[] content) throws Exception{
+        FileApi api = SpringContextHolder.getBean(FileApi.class);
+        Result<FileInfoDTO> result = api.upload(null,
+                new ByteArrayMultipartFile(fileName, contentType, content));
+        if (result.isSuccess()) {
+            return result.getData();
+        } else {
+            throw new BizException(result.getCode(), result.getMessage());
+        }
+    }
+
+}

+ 0 - 4
base-servers/file/file-dto/pom.xml

@@ -17,10 +17,6 @@
             <artifactId>springfox-swagger2</artifactId>
             <scope>compile</scope>
         </dependency>
-      <dependency>
-        <groupId>org.springframework</groupId>
-        <artifactId>spring-web</artifactId>
-      </dependency>
     </dependencies>
 
 </project>

+ 17 - 4
base-servers/file/file-dto/src/main/java/com/usoftchina/smartschool/file/dto/FileInfoDTO.java

@@ -15,11 +15,17 @@ public class FileInfoDTO extends BaseFileInfo implements Serializable {
     private Long id;
 
     /**
-     * 链接
+     * 存储路径
      */
-    @ApiModelProperty(value = "文件path")
+    @ApiModelProperty(value = "文件存储path")
     private String fullPath;
 
+    /**
+     * 访问链接
+     */
+    @ApiModelProperty(value = "文件访问path")
+    private String accessPath;
+
     /**
      * 类型
      */
@@ -67,6 +73,14 @@ public class FileInfoDTO extends BaseFileInfo implements Serializable {
         this.mime = mime;
     }
 
+    public String getAccessPath() {
+        return accessPath;
+    }
+
+    public void setAccessPath(String accessPath) {
+        this.accessPath = accessPath;
+    }
+
     public String getExt() {
         return ext;
     }
@@ -95,9 +109,8 @@ public class FileInfoDTO extends BaseFileInfo implements Serializable {
     public String toString() {
         return "FileInfoDTO{" +
                 "id=" + id +
-                ", folderId=" + folderId +
-                ", name=" + name +
                 ", fullPath='" + fullPath + '\'' +
+                ", accessPath='" + accessPath + '\'' +
                 ", mime='" + mime + '\'' +
                 ", ext='" + ext + '\'' +
                 ", size=" + size +

+ 41 - 0
base-servers/file/file-server-fdfs/pom.xml

@@ -0,0 +1,41 @@
+<?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>file</artifactId>
+        <groupId>com.usoftchina.smartschool</groupId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>file-server-fdfs</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>file-server</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>file-storage-fdfs</artifactId>
+        </dependency>
+        <!-- test -->
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>test-starter</artifactId>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>com.spotify</groupId>
+                <artifactId>docker-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 1 - 1
base-servers/file/file-server/src/main/docker/Dockerfile → base-servers/file/file-server-fdfs/src/main/docker/Dockerfile

@@ -1,6 +1,6 @@
 FROM frolvlad/alpine-oraclejdk8:slim
 VOLUME /tmp
-ADD file-server-1.0.0-SNAPSHOT.jar app.jar
+ADD file-server-fdfs-1.0.0-SNAPSHOT.jar app.jar
 RUN sh -c 'touch /app.jar'
 ENV JAVA_OPTS=""
 ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]

+ 5 - 8
base-servers/file/file-server/src/main/java/com/usoftchina/smartschool/file/FileApplication.java → base-servers/file/file-server-fdfs/src/main/java/com/usoftchina/smartschool/file/fdfs/FdfsFileApplication.java

@@ -1,29 +1,26 @@
-package com.usoftchina.smartschool.file;
+package com.usoftchina.smartschool.file.fdfs;
 
-import com.github.tobato.fastdfs.FdfsClientConfig;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
 import org.springframework.context.annotation.EnableMBeanExport;
-import org.springframework.context.annotation.Import;
 import org.springframework.jmx.support.RegistrationPolicy;
 import org.springframework.transaction.annotation.EnableTransactionManagement;
 import springfox.documentation.swagger2.annotations.EnableSwagger2;
 
 /**
  * @author yingp
- * @date 2018/9/29
+ * @date 2019/3/14
  */
-@SpringBootApplication
+@SpringBootApplication(scanBasePackages = "com.usoftchina.smartschool.file")
 @EnableEurekaClient
 @EnableTransactionManagement
 @MapperScan("com.usoftchina.smartschool.file.mapper")
-@Import(FdfsClientConfig.class)
 @EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
 @EnableSwagger2
-public class FileApplication {
+public class FdfsFileApplication {
     public static void main(String[] args) {
-        SpringApplication.run(FileApplication.class, args);
+        SpringApplication.run(FdfsFileApplication.class, args);
     }
 }

+ 11 - 11
base-servers/file/file-server/src/main/resources/application.yml → base-servers/file/file-server-fdfs/src/main/resources/application.yml

@@ -1,3 +1,13 @@
+fdfs:
+  so-timeout: 1500
+  connect-timeout: 600
+  thumb-image:
+    width: 150
+    height: 150
+  tracker-list:
+    - 10.10.100.200:22122
+file:
+  base-url: http://10.1.81.1:8888/
 spring:
   application:
     name: file-server
@@ -86,14 +96,4 @@ mybatis:
   type-aliases-package: com.usoftchina.smartschool.file.po
   mapper-locations: classpath:mapper/*.xml
 auth:
-  public-key: auth/pub.key
-fdfs:
-  so-timeout: 1500
-  connect-timeout: 600
-  thumb-image:
-    width: 150
-    height: 150
-  tracker-list:
-    - 10.1.81.1:22122
-file:
-  base-url: http://10.1.81.1:8888/
+  public-key: auth/pub.key

+ 1 - 4
base-servers/file/file-server/src/main/resources/config/application-docker-prod.yml → base-servers/file/file-server-fdfs/src/main/resources/config/application-docker-prod.yml

@@ -4,7 +4,4 @@ eureka:
     prefer-ip-address: false
   client:
     serviceUrl:
-      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@smartschool-eureka-server:9500/eureka/
-fdfs:
-  tracker-list:
-    - 10.10.100.200:22122
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@smartschool-eureka-server:9500/eureka/

+ 0 - 0
base-servers/file/file-server/src/main/resources/config/application-docker.yml → base-servers/file/file-server-fdfs/src/main/resources/config/application-docker.yml


+ 0 - 0
base-servers/file/file-server/src/main/resources/logback-spring.xml → base-servers/file/file-server-fdfs/src/main/resources/logback-spring.xml


+ 41 - 0
base-servers/file/file-server-qcloud/pom.xml

@@ -0,0 +1,41 @@
+<?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>file</artifactId>
+        <groupId>com.usoftchina.smartschool</groupId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>file-server-qcloud</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>file-server</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>file-storage-qcloud</artifactId>
+        </dependency>
+        <!-- test -->
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>test-starter</artifactId>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>com.spotify</groupId>
+                <artifactId>docker-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 6 - 0
base-servers/file/file-server-qcloud/src/main/docker/Dockerfile

@@ -0,0 +1,6 @@
+FROM frolvlad/alpine-oraclejdk8:slim
+VOLUME /tmp
+ADD file-server-qcloud-1.0.0-SNAPSHOT.jar app.jar
+RUN sh -c 'touch /app.jar'
+ENV JAVA_OPTS=""
+ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]

+ 26 - 0
base-servers/file/file-server-qcloud/src/main/java/com/usoftchina/smartschool/file/qcloud/QCloudFileApplication.java

@@ -0,0 +1,26 @@
+package com.usoftchina.smartschool.file.qcloud;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.context.annotation.EnableMBeanExport;
+import org.springframework.jmx.support.RegistrationPolicy;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+/**
+ * @author yingp
+ * @date 2019/3/14
+ */
+@SpringBootApplication(scanBasePackages = "com.usoftchina.smartschool.file")
+@EnableEurekaClient
+@EnableTransactionManagement
+@MapperScan("com.usoftchina.smartschool.file.mapper")
+@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
+@EnableSwagger2
+public class QCloudFileApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(QCloudFileApplication.class, args);
+    }
+}

+ 97 - 0
base-servers/file/file-server-qcloud/src/main/resources/application.yml

@@ -0,0 +1,97 @@
+qcloud:
+  cos:
+    secretId: AKIDngQ1QbKfRHxOcl6QxG5jIxcQ3YelYKUR
+    secretKey: ykGDn9HYAZkOs30oPxNcqgoyWvSnqfGf
+    region: ap-chengdu
+    bucketName: ydy-1258516134
+file:
+  base-url: https://${qcloud.cos.bucketName}.cos.${qcloud.cos.region}.myqcloud.com/
+spring:
+  application:
+    name: file-server
+  security:
+    user:
+      name: admin
+      password: select111***
+  rabbitmq:
+    host: 10.10.100.166
+    port: 5672
+    virtual-host: school
+    username: school
+    password: select123***
+  zipkin:
+    sender:
+      type: rabbit
+    locator:
+      discovery:
+        enabled: true
+  sleuth:
+    sampler:
+      probability: 1.0
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://10.10.100.166:3306/smart_campus?characterEncoding=utf-8&useSSL=false
+    username: root
+    password: select111***
+    hikari:
+      minimum-idle: 5
+      maximum-pool-size: 50
+      idle-timeout: 30000
+      max-lifetime: 1800000
+      connection-timeout: 30000
+  messages:
+    basename: i18n/messages
+  redis:
+    host: 10.10.100.166
+    port: 6379
+  jackson:
+    date-format: yyyy-MM-dd HH:mm:ss
+    time-zone: GMT+8
+  profiles:
+    active: dev
+  servlet:
+    multipart:
+      enabled: true
+      #20971520 ->  20M
+      max-file-size: 20971520
+      max-request-size: 20971520
+eureka:
+  instance:
+    leaseRenewalIntervalInSeconds: 10
+    health-check-url-path: /actuator/health
+    status-page-url-path: /actuator/info
+    prefer-ip-address: true
+    metadata-map:
+      user.name: ${spring.security.user.name}
+      user.password: ${spring.security.user.password}
+  client:
+    registryFetchIntervalSeconds: 5
+    serviceUrl:
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@127.0.0.1:9500/eureka/
+server:
+  port: 9540
+  tomcat:
+    uri-encoding: UTF-8
+management:
+  endpoints:
+    web:
+      exposure:
+        include: "*"
+  endpoint:
+    health:
+      show-details: always
+    shutdown:
+      enabled: true
+    restart:
+      enabled: true
+info:
+  name: '@project.artifactId@'
+  description: '@project.description@'
+  version: '@project.version@'
+  spring-boot-version: '@spring.boot.version@'
+  spring-cloud-version: '@spring.cloud.version@'
+mybatis:
+  type-aliases-package: com.usoftchina.smartschool.file.po
+  mapper-locations: classpath:mapper/*.xml
+auth:
+  public-key: auth/pub.key

+ 29 - 0
base-servers/file/file-server-qcloud/src/main/resources/config/application-docker-cloud.yml

@@ -0,0 +1,29 @@
+eureka:
+  instance:
+    hostname: smartschool-file-server
+    prefer-ip-address: false
+  client:
+    serviceUrl:
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@smartschool-eureka-server:9500/eureka/
+  spring:
+    redis:
+      host: 172.27.0.13
+      port: 6379
+      password: select111***
+    datasource:
+        driver-class-name: com.mysql.jdbc.Driver
+        url: jdbc:mysql://172.27.0.15:3306/smart_campus?characterEncoding=utf-8&useSSL=false&allowMultiQueries=true
+        username: root
+        password: select111***
+        hikari:
+          minimum-idle: 5
+          maximum-pool-size: 50
+          idle-timeout: 30000
+          max-lifetime: 1800000
+          connection-timeout: 30000
+    rabbitmq:
+          host: 132.232.174.14
+          port: 5672
+          virtual-host: school
+          username: saas
+          password: select123***

+ 7 - 0
base-servers/file/file-server-qcloud/src/main/resources/config/application-docker-prod.yml

@@ -0,0 +1,7 @@
+eureka:
+  instance:
+    hostname: smartschool-file-server
+    prefer-ip-address: false
+  client:
+    serviceUrl:
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@smartschool-eureka-server:9500/eureka/

+ 131 - 0
base-servers/file/file-server-qcloud/src/main/resources/logback-spring.xml

@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <include resource="org/springframework/boot/logging/logback/base.xml" />
+    <jmxConfigurator/>
+
+    <!--
+    %m
+    输出代码中指定的消息
+    %p
+    输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
+    %r
+    输出自应用启动到输出该log信息耗费的毫秒数
+    %c
+    输出所属的类目,通常就是所在类的全名
+    %t
+    输出产生该日志事件的线程名
+    %n
+    输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n”
+    %d
+    输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},
+    输出类似:2002年10月18日 22:10:28,921
+    %l
+    输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)
+    -->
+
+    <springProperty scope="context" name="log.path" source="logging.path" defaultValue="/var/log/smartschool/file-server"/>
+    <springProperty scope="context" name="spring.application.name" source="spring.application.name" defaultValue="file-server"/>
+    <springProperty scope="context" name="spring.profiles.active" source="spring.profiles.active" defaultValue="dev"/>
+    <springProperty scope="context" name="common-pattern" source="logging.common-pattern" defaultValue="%d{yyyy-MM-dd HH:mm:ss.SSS}:[%5p] [%t:%r] [%C{1}:%M:%L] --> %m%n"/>
+    <springProperty scope="context" name="log.level.console" source="logging.level.console" defaultValue="INFO"/>
+    <springProperty scope="context" name="log.destination" source="logging.destination" defaultValue="10.1.81.1:5000"/>
+
+    <contextName>${spring.application.name}-${spring.profiles.active}-logback</contextName>
+
+    <appender name="CONSOLE_APPENDER" class="ch.qos.logback.core.ConsoleAppender">
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>${log.level.console}</level>
+        </filter>
+        <encoder>
+            <pattern>${common-pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <appender name="ROOT_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/root.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${log.path}/%d{yyyy-MM}/root-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>
+            <maxFileSize>128MB</maxFileSize>
+            <maxHistory>7</maxHistory>
+            <totalSizeCap>20GB</totalSizeCap>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${common-pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <!-- Appender to log in a JSON format -->
+    <appender name="JSON_APPENDER" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
+        <destination>${log.destination}</destination>
+        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
+            <providers>
+                <pattern>
+                    <pattern>
+                        {
+                        "severity": "%level",
+                        "service": "${spring.application.name:-}",
+                        "trace": "%X{X-B3-TraceId:-}",
+                        "span": "%X{X-B3-SpanId:-}",
+                        "parent": "%X{X-B3-ParentSpanId:-}",
+                        "exportable": "%X{X-Span-Export:-}",
+                        "pid": "${PID:-}",
+                        "thread": "%thread",
+                        "class": "%logger{40}",
+                        "rest": "%message"
+                        }
+                    </pattern>
+                </pattern>
+            </providers>
+        </encoder>
+    </appender>
+
+    <logger name="org.springframework" level="INFO"/>
+    <logger name="com.usoftchina.smartschool" level="INFO"/>
+
+    <springProfile name="dev">
+        <root level="INFO">
+            <appender-ref ref="CONSOLE_APPENDER"/>
+        </root>
+    </springProfile>
+
+    <springProfile name="test">
+        <root level="INFO">
+            <appender-ref ref="CONSOLE_APPENDER"/>
+            <appender-ref ref="ROOT_APPENDER"/>
+        </root>
+    </springProfile>
+
+    <springProfile name="docker">
+        <logger name="org.springframework" level="WARN"/>
+        <logger name="com.usoftchina.smartschool" level="WARN"/>
+        <root level="WARN">
+            <appender-ref ref="CONSOLE_APPENDER"/>
+            <appender-ref ref="JSON_APPENDER"/>
+        </root>
+    </springProfile>
+
+    <springProfile name="docker-dev">
+        <root level="INFO">
+            <appender-ref ref="CONSOLE_APPENDER"/>
+        </root>
+    </springProfile>
+
+    <springProfile name="docker-test">
+        <logger name="org.springframework" level="WARN"/>
+        <logger name="com.usoftchina.smartschool" level="WARN"/>
+        <root level="WARN">
+            <appender-ref ref="CONSOLE_APPENDER"/>
+            <appender-ref ref="JSON_APPENDER"/>
+        </root>
+    </springProfile>
+
+    <springProfile name="docker-prod">
+        <logger name="org.springframework" level="WARN"/>
+        <logger name="com.usoftchina.smartschool" level="WARN"/>
+        <root level="WARN">
+            <appender-ref ref="CONSOLE_APPENDER"/>
+            <appender-ref ref="JSON_APPENDER"/>
+        </root>
+    </springProfile>
+
+</configuration>

+ 2 - 19
base-servers/file/file-server/pom.xml

@@ -48,8 +48,8 @@
         </dependency>
 
         <dependency>
-            <groupId>com.github.tobato</groupId>
-            <artifactId>fastdfs-client</artifactId>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>file-storage</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>
@@ -68,23 +68,6 @@
             <groupId>net.logstash.logback</groupId>
             <artifactId>logstash-logback-encoder</artifactId>
         </dependency>
-        <!-- test -->
-        <dependency>
-            <groupId>com.usoftchina.smartschool</groupId>
-            <artifactId>test-starter</artifactId>
-        </dependency>
     </dependencies>
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.springframework.boot</groupId>
-                <artifactId>spring-boot-maven-plugin</artifactId>
-            </plugin>
-            <plugin>
-                <groupId>com.spotify</groupId>
-                <artifactId>docker-maven-plugin</artifactId>
-            </plugin>
-        </plugins>
-    </build>
 
 </project>

+ 6 - 25
base-servers/file/file-server/src/main/java/com/usoftchina/smartschool/file/controller/FileController.java

@@ -1,7 +1,5 @@
 package com.usoftchina.smartschool.file.controller;
 
-import com.github.tobato.fastdfs.domain.StorePath;
-import com.github.tobato.fastdfs.service.FastFileStorageClient;
 import com.usoftchina.smartschool.base.Result;
 import com.usoftchina.smartschool.exception.BizException;
 import com.usoftchina.smartschool.exception.ExceptionCode;
@@ -9,6 +7,7 @@ import com.usoftchina.smartschool.file.constant.FileConstant;
 import com.usoftchina.smartschool.file.dto.*;
 import com.usoftchina.smartschool.file.po.FileInfo;
 import com.usoftchina.smartschool.file.service.FileInfoService;
+import com.usoftchina.smartschool.file.storage.FileStorageClient;
 import com.usoftchina.smartschool.utils.BeanMapper;
 import com.usoftchina.smartschool.utils.BizAssert;
 import com.usoftchina.smartschool.utils.CollectionUtils;
@@ -18,7 +17,6 @@ import io.swagger.annotations.ApiOperation;
 import org.apache.commons.compress.archivers.ArchiveOutputStream;
 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
 import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
-import org.apache.commons.io.IOUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.http.MediaType;
@@ -46,7 +44,7 @@ public class FileController {
     private FileInfoService fileService;
 
     @Autowired
-    private FastFileStorageClient storageClient;
+    private FileStorageClient storageClient;
     /**
      * 文件访问服务baseUrl
      *
@@ -96,19 +94,7 @@ public class FileController {
         // 检查父文件夹
         FileInfo parent = checkFolder(folderId);
         FileInfo info = FileInfo.newFile(file).folder(parent.getId())
-                .storeBy(storageClient).build();
-        fileService.save(info);
-        return Result.success(BeanMapper.map(info, FileInfoDTO.class));
-    }
-
-    @ApiOperation(value = "上传文件")
-    @PostMapping(value = "/imageUpload")
-    public Result<FileInfoDTO> imageUpload(@RequestBody ImageFile imageFile) throws Exception {
-        // 检查父文件夹
-        FileInfo parent = checkFolder(0L);
-        MultipartFile file = new MyMultipartFile(imageFile.getName(), imageFile.getName()+ ".jpg", imageFile.getContent()) ;
-        FileInfo info = FileInfo.newFile(file).folder(parent.getId())
-                .storeBy(storageClient).build();
+                .storeBy(storageClient).baseUrl(fileBaseUrl).build();
         fileService.save(info);
         return Result.success(BeanMapper.map(info, FileInfoDTO.class));
     }
@@ -137,9 +123,7 @@ public class FileController {
             if (null != info.getFullPath()) {
                 response.setHeader("Content-disposition",
                         "attachment; filename=" + URLEncoder.encode(info.getName(), "UTF-8"));
-                StorePath path = StorePath.praseFromUrl(info.getFullPath());
-                storageClient.downloadFile(path.getGroup(), path.getPath(),
-                        in -> IOUtils.copy(in, response.getOutputStream()));
+                storageClient.downloadFile(info.getFullPath(), response.getOutputStream());
             }
         }
     }
@@ -169,9 +153,7 @@ public class FileController {
             if (!StringUtils.isEmpty(info.getMime())) {
                 response.setContentType(info.getMime());
             }
-            StorePath path = StorePath.praseFromUrl(info.getFullPath());
-            storageClient.downloadFile(path.getGroup(), path.getPath(),
-                    in -> IOUtils.copy(in, response.getOutputStream()));
+            storageClient.downloadFile(info.getFullPath(), response.getOutputStream());
         } else {
             // 无法直接查看的文件,下载到客户端
             download(info.getId(), response);
@@ -258,8 +240,7 @@ public class FileController {
             }
         } else {
             out.putArchiveEntry(new ZipArchiveEntry(directory + info.getName()));
-            StorePath path = StorePath.praseFromUrl(info.getFullPath());
-            storageClient.downloadFile(path.getGroup(), path.getPath(), in -> IOUtils.copy(in, out));
+            storageClient.downloadFile(info.getFullPath(), out);
             out.closeArchiveEntry();
         }
     }

+ 31 - 29
base-servers/file/file-server/src/main/java/com/usoftchina/smartschool/file/po/FileInfo.java

@@ -1,14 +1,14 @@
 package com.usoftchina.smartschool.file.po;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.github.tobato.fastdfs.domain.StorePath;
-import com.github.tobato.fastdfs.service.FastFileStorageClient;
 import com.usoftchina.smartschool.base.entity.CommonBaseEntity;
 import com.usoftchina.smartschool.context.BaseContextHolder;
-import com.usoftchina.smartschool.file.constant.FileType;
-import com.usoftchina.smartschool.file.util.FileTypeUtils;
+import com.usoftchina.smartschool.file.storage.FileMetadata;
+import com.usoftchina.smartschool.file.storage.FileStorageClient;
+import com.usoftchina.smartschool.file.storage.util.FileType;
+import com.usoftchina.smartschool.file.storage.util.FileTypeUtils;
+import com.usoftchina.smartschool.file.storage.util.FilenameUtils;
 import com.usoftchina.smartschool.utils.StringUtils;
-import org.apache.commons.io.FilenameUtils;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.io.IOException;
@@ -19,7 +19,7 @@ import java.util.Date;
  * @author yingp
  * @date 2018/9/29
  */
-public class FileInfo extends CommonBaseEntity implements Serializable{
+public class FileInfo extends CommonBaseEntity implements Serializable {
     /**
      * 文件夹id
      */
@@ -33,6 +33,10 @@ public class FileInfo extends CommonBaseEntity implements Serializable{
      * 存储路径
      */
     private String fullPath;
+    /**
+     * 访问路径
+     */
+    private String accessPath;
     /**
      * Content-Type
      */
@@ -47,7 +51,8 @@ public class FileInfo extends CommonBaseEntity implements Serializable{
     private long size;
     /**
      * 类型
-     * @see com.usoftchina.smartschool.file.constant.FileType
+     *
+     * @see com.usoftchina.smartschool.file.storage.util.FileType
      */
     private String type;
 
@@ -76,10 +81,11 @@ public class FileInfo extends CommonBaseEntity implements Serializable{
         this.name = name;
     }
 
-    public FileInfo(Long folderId, String name, String fullPath, String mime, String ext, String type, long size) {
+    public FileInfo(Long folderId, String name, String fullPath, String accessPath, String mime, String ext, String type, long size) {
         this.folderId = folderId;
         this.name = name;
         this.fullPath = fullPath;
+        this.accessPath = accessPath;
         this.mime = mime;
         this.ext = ext;
         this.type = type;
@@ -142,6 +148,14 @@ public class FileInfo extends CommonBaseEntity implements Serializable{
         this.type = type;
     }
 
+    public String getAccessPath() {
+        return accessPath;
+    }
+
+    public void setAccessPath(String accessPath) {
+        this.accessPath = accessPath;
+    }
+
     public boolean isDeleted() {
         return deleted;
     }
@@ -211,7 +225,7 @@ public class FileInfo extends CommonBaseEntity implements Serializable{
         return info;
     }
 
-    public static Builder newFile(MultipartFile file){
+    public static Builder newFile(MultipartFile file) {
         return new Builder(file);
     }
 
@@ -227,7 +241,7 @@ public class FileInfo extends CommonBaseEntity implements Serializable{
         private long size;
         private String type;
         private MultipartFile multipartFile;
-        private FastFileStorageClient storageClient;
+        private FileStorageClient storageClient;
         private String baseUrl;
 
         public Builder(MultipartFile file) {
@@ -274,7 +288,7 @@ public class FileInfo extends CommonBaseEntity implements Serializable{
             return this;
         }
 
-        public Builder storeBy(FastFileStorageClient storageClient){
+        public Builder storeBy(FileStorageClient storageClient) {
             this.storageClient = storageClient;
             return this;
         }
@@ -284,26 +298,14 @@ public class FileInfo extends CommonBaseEntity implements Serializable{
             return this;
         }
 
-        public FileInfo build() throws IOException{
+        public FileInfo build() throws IOException {
             if (null != storageClient) {
-                StorePath storePath;
-                if (FileType.of(type) == FileType.IMAGE) {
-                    // 保存图片 + 生成缩略图
-                    try {
-                        storePath = storageClient.uploadImageAndCrtThumbImage(multipartFile.getInputStream(),
-                                size, ext, null);
-                    }catch (Exception e) {
-                        storePath = storageClient.uploadFile(multipartFile.getInputStream(),
-                                size, ext, null);
-                    }
-                } else {
-                    storePath = storageClient.uploadFile(multipartFile.getInputStream(),
-                            size, ext, null);
-                }
-                this.fullPath = StringUtils.nullIf(baseUrl) + storePath.getFullPath();
+                this.fullPath = storageClient.uploadFile(multipartFile.getInputStream(),
+                        new FileMetadata(mime, ext, size));
             }
 
-            return new FileInfo(folderId, name, fullPath, mime, ext, type, size);
+            String accessPath = StringUtils.nullIf(baseUrl) + fullPath;
+            return new FileInfo(folderId, name, fullPath, accessPath, mime, ext, type, size);
         }
     }
-}
+}

+ 0 - 13
base-servers/file/file-server/src/main/resources/config/application-dev.yml

@@ -1,13 +0,0 @@
-eureka:
-  instance:
-    leaseRenewalIntervalInSeconds: 10
-    health-check-url-path: /actuator/health
-    status-page-url-path: /actuator/info
-    prefer-ip-address: true
-    metadata-map:
-      user.name: ${spring.security.user.name}
-      user.password: ${spring.security.user.password}
-  client:
-    registryFetchIntervalSeconds: 5
-    serviceUrl:
-      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@127.0.0.1:9500/eureka/

+ 0 - 12
base-servers/file/file-server/src/main/resources/config/application-docker-dev.yml

@@ -1,12 +0,0 @@
-eureka:
-  instance:
-    hostname: saas-file-server-dev
-    prefer-ip-address: false
-  client:
-    serviceUrl:
-      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@saas-eureka-server-dev:8510/eureka/
-spring:
-  rabbitmq:
-    virtual-host: dev
-server:
-  port: 8650

+ 0 - 12
base-servers/file/file-server/src/main/resources/config/application-docker-test.yml

@@ -1,12 +0,0 @@
-eureka:
-  instance:
-    hostname: saas-file-server-test
-    prefer-ip-address: false
-  client:
-    serviceUrl:
-      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@saas-eureka-server-test:8515/eureka/
-spring:
-  rabbitmq:
-    virtual-host: test
-server:
-  port: 8655

+ 0 - 0
base-servers/file/file-server/src/main/resources/i18n/messages_en_US.properties


+ 0 - 0
base-servers/file/file-server/src/main/resources/i18n/messages_zh_CN.properties


+ 24 - 0
base-servers/file/file-storage-fdfs/pom.xml

@@ -0,0 +1,24 @@
+<?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>file</artifactId>
+        <groupId>com.usoftchina.smartschool</groupId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>file-storage-fdfs</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.github.tobato</groupId>
+            <artifactId>fastdfs-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>file-storage</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 21 - 0
base-servers/file/file-storage-fdfs/src/main/java/com/usoftchina/smartschool/file/storage/fdfs/FdfsConfig.java

@@ -0,0 +1,21 @@
+package com.usoftchina.smartschool.file.storage.fdfs;
+
+import com.github.tobato.fastdfs.FdfsClientConfig;
+import com.usoftchina.smartschool.file.storage.FileStorageClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+/**
+ * @author yingp
+ * @date 2019/3/14
+ */
+@Configuration
+@Import(FdfsClientConfig.class)
+public class FdfsConfig {
+
+    @Bean
+    public FileStorageClient fileStorageClient() {
+        return new FdfsFileStorageClient();
+    }
+}

+ 50 - 0
base-servers/file/file-storage-fdfs/src/main/java/com/usoftchina/smartschool/file/storage/fdfs/FdfsFileStorageClient.java

@@ -0,0 +1,50 @@
+package com.usoftchina.smartschool.file.storage.fdfs;
+
+import com.github.tobato.fastdfs.domain.StorePath;
+import com.github.tobato.fastdfs.service.FastFileStorageClient;
+import com.usoftchina.smartschool.file.storage.FileMetadata;
+import com.usoftchina.smartschool.file.storage.FileStorageClient;
+import com.usoftchina.smartschool.file.storage.util.FileType;
+import com.usoftchina.smartschool.file.storage.util.FileTypeUtils;
+import org.apache.commons.io.IOUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * @author yingp
+ * @date 2019/3/14
+ */
+public class FdfsFileStorageClient implements FileStorageClient{
+
+    @Autowired
+    private FastFileStorageClient storageClient;
+
+    @Override
+    public String uploadFile(InputStream inputStream, FileMetadata metadata) {
+        FileType type = FileTypeUtils.getFileType(metadata.getMime(), metadata.getExt());
+        StorePath storePath;
+        if (FileType.IMAGE == type) {
+            // 保存图片 + 生成缩略图
+            storePath = storageClient.uploadImageAndCrtThumbImage(inputStream, metadata.getSize(),
+                    metadata.getExt(), null);
+        } else {
+            storePath = storageClient.uploadFile(inputStream, metadata.getSize(),
+                    metadata.getExt(), null);
+        }
+        return storePath.getFullPath();
+    }
+
+    @Override
+    public void deleteFile(String filePath) {
+        storageClient.deleteFile(filePath);
+    }
+
+    @Override
+    public void downloadFile(String filePath, OutputStream out) throws IOException{
+        StorePath path = StorePath.praseFromUrl(filePath);
+        storageClient.downloadFile(path.getGroup(), path.getPath(), in -> IOUtils.copy(in, out));
+    }
+}

+ 3 - 0
base-servers/file/file-storage-fdfs/src/main/resources/META-INF/spring.factories

@@ -0,0 +1,3 @@
+# Auto Configuration
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+com.usoftchina.smartschool.file.storage.fdfs.FdfsConfig

+ 35 - 0
base-servers/file/file-storage-qcloud/pom.xml

@@ -0,0 +1,35 @@
+<?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>file</artifactId>
+        <groupId>com.usoftchina.smartschool</groupId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>file-storage-qcloud</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.qcloud</groupId>
+            <artifactId>cos_api</artifactId>
+            <version>5.4.10</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-log4j12</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>file-storage</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 81 - 0
base-servers/file/file-storage-qcloud/src/main/java/com/usoftchina/smartschool/file/storage/qcloud/COSFileStorageClient.java

@@ -0,0 +1,81 @@
+package com.usoftchina.smartschool.file.storage.qcloud;
+
+import com.qcloud.cos.COSClient;
+import com.qcloud.cos.ClientConfig;
+import com.qcloud.cos.auth.BasicCOSCredentials;
+import com.qcloud.cos.auth.COSCredentials;
+import com.qcloud.cos.model.COSObject;
+import com.qcloud.cos.model.ObjectMetadata;
+import com.qcloud.cos.region.Region;
+import com.qcloud.cos.utils.IOUtils;
+import com.usoftchina.smartschool.file.storage.FileMetadata;
+import com.usoftchina.smartschool.file.storage.FileStorageClient;
+import org.springframework.util.StringUtils;
+
+import javax.annotation.PreDestroy;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.UUID;
+
+/**
+ * @author yingp
+ * @date 2019/3/14
+ */
+public class COSFileStorageClient implements FileStorageClient {
+
+    private final CosProperties cosProperties;
+    private final COSClient client;
+
+    public COSFileStorageClient(CosProperties cosProperties) {
+        this.cosProperties = cosProperties;
+        this.client = initCOSClient();
+    }
+
+    private COSClient initCOSClient() {
+        // 1 初始化用户身份信息
+        COSCredentials cred = new BasicCOSCredentials(cosProperties.getSecretId(),
+                cosProperties.getSecretKey());
+        // 2 设置bucket的区域
+        ClientConfig clientConfig = new ClientConfig(new Region(cosProperties.getRegion()));
+        // 3 生成 cos 客户端。
+        return new COSClient(cred, clientConfig);
+    }
+
+    @Override
+    public String uploadFile(InputStream inputStream, FileMetadata metadata) {
+        ObjectMetadata objectMetadata = new ObjectMetadata();
+        objectMetadata.setContentLength(metadata.getSize());
+        if (!StringUtils.isEmpty(metadata.getMime())) {
+            objectMetadata.setContentType(metadata.getMime());
+        }
+        String filePath = generateDefaultFilePath() +
+                (StringUtils.isEmpty(metadata.getExt()) ? "" : ("." + metadata.getExt()));
+        client.putObject(cosProperties.getBucketName(), filePath, inputStream, objectMetadata);
+        return filePath;
+    }
+
+    private String generateDefaultFilePath() {
+        // 当天 + 随机串
+        return LocalDateTime.now().format(DateTimeFormatter.ISO_DATE) + "/" +
+                UUID.randomUUID().toString();
+    }
+
+    @Override
+    public void deleteFile(String filePath) {
+        client.deleteObject(cosProperties.getBucketName(), filePath);
+    }
+
+    @PreDestroy
+    public void shutdown() {
+        client.shutdown();
+    }
+
+    @Override
+    public void downloadFile(String filePath, OutputStream out) throws IOException {
+        COSObject object = client.getObject(cosProperties.getBucketName(), filePath);
+        IOUtils.copy(object.getObjectContent(), out);
+    }
+}

+ 58 - 0
base-servers/file/file-storage-qcloud/src/main/java/com/usoftchina/smartschool/file/storage/qcloud/CosProperties.java

@@ -0,0 +1,58 @@
+package com.usoftchina.smartschool.file.storage.qcloud;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * @author yingp
+ * @date 2019/3/14
+ */
+@ConfigurationProperties(CosProperties.PREFIX)
+public class CosProperties {
+    public static final String PREFIX = "qcloud.cos";
+
+    /**
+     * 秘钥
+     */
+    private String secretId;
+    private String secretKey;
+    /**
+     * 所属地域
+     */
+    private String region;
+    /**
+     * 存储桶名称
+     */
+    private String bucketName;
+
+    public String getSecretId() {
+        return secretId;
+    }
+
+    public void setSecretId(String secretId) {
+        this.secretId = secretId;
+    }
+
+    public String getSecretKey() {
+        return secretKey;
+    }
+
+    public void setSecretKey(String secretKey) {
+        this.secretKey = secretKey;
+    }
+
+    public String getRegion() {
+        return region;
+    }
+
+    public void setRegion(String region) {
+        this.region = region;
+    }
+
+    public String getBucketName() {
+        return bucketName;
+    }
+
+    public void setBucketName(String bucketName) {
+        this.bucketName = bucketName;
+    }
+}

+ 24 - 0
base-servers/file/file-storage-qcloud/src/main/java/com/usoftchina/smartschool/file/storage/qcloud/QCloudConfig.java

@@ -0,0 +1,24 @@
+package com.usoftchina.smartschool.file.storage.qcloud;
+
+import com.usoftchina.smartschool.file.storage.FileStorageClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author yingp
+ * @date 2019/3/14
+ */
+@Configuration
+@EnableConfigurationProperties(CosProperties.class)
+public class QCloudConfig {
+
+    @Autowired
+    private CosProperties cosProperties;
+
+    @Bean
+    public FileStorageClient fileStorageClient() {
+        return new COSFileStorageClient(cosProperties);
+    }
+}

+ 3 - 0
base-servers/file/file-storage-qcloud/src/main/resources/META-INF/spring.factories

@@ -0,0 +1,3 @@
+# Auto Configuration
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+com.usoftchina.smartschool.file.storage.qcloud.QCloudConfig

+ 37 - 0
base-servers/file/file-storage-qcloud/src/test/java/com/usoftchina/smartschool/file/storage/qcloud/COSFileStorageClientTest.java

@@ -0,0 +1,37 @@
+package com.usoftchina.smartschool.file.storage.qcloud;
+
+import com.usoftchina.smartschool.file.storage.FileMetadata;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * @author yingp
+ * @date 2019/3/14
+ */
+public class COSFileStorageClientTest {
+    private static COSFileStorageClient getClient() {
+        CosProperties properties = new CosProperties();
+        properties.setSecretId("AKIDngQ1QbKfRHxOcl6QxG5jIxcQ3YelYKUR");
+        properties.setSecretKey("ykGDn9HYAZkOs30oPxNcqgoyWvSnqfGf");
+        properties.setRegion("ap-chengdu");
+        properties.setBucketName("ydy-1258516134");
+        return new COSFileStorageClient(properties);
+    }
+
+    public static void main(String[] args) throws IOException{
+        RandomTextFile file = new RandomTextFile();
+        COSFileStorageClient client = getClient();
+        try {
+            String filePath = client.uploadFile(file.getInputStream(), new FileMetadata(null,
+                    file.getFileExtName(), file.getFileSize()));
+            System.out.println(filePath);
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            client.downloadFile(filePath, out);
+            assert file.getText().equals(out.toString());
+            client.deleteFile(filePath);
+        } finally {
+            client.shutdown();
+        }
+    }
+}

+ 49 - 0
base-servers/file/file-storage-qcloud/src/test/java/com/usoftchina/smartschool/file/storage/qcloud/RandomTextFile.java

@@ -0,0 +1,49 @@
+package com.usoftchina.smartschool.file.storage.qcloud;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.UUID;
+
+/**
+ * @author yingp
+ * @date 2018/11/9
+ */
+public class RandomTextFile {
+    private String text;
+
+    private InputStream inputStream;
+
+    private long fileSize;
+
+    private String fileExtName = "text";
+
+    public RandomTextFile() {
+        this(UUID.randomUUID().toString());
+    }
+
+    public RandomTextFile(String text) {
+        this.text = text;
+        this.fileSize = text.getBytes().length;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public InputStream getInputStream() {
+        this.inputStream = new ByteArrayInputStream(text.getBytes());
+        return inputStream;
+    }
+
+    public long getFileSize() {
+        return fileSize;
+    }
+
+    public String getFileExtName() {
+        return fileExtName;
+    }
+
+    public byte[] toByte() {
+        return this.text.getBytes();
+    }
+}

+ 15 - 0
base-servers/file/file-storage/pom.xml

@@ -0,0 +1,15 @@
+<?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>file</artifactId>
+        <groupId>com.usoftchina.smartschool</groupId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>file-storage</artifactId>
+
+
+</project>

+ 44 - 0
base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/FileMetadata.java

@@ -0,0 +1,44 @@
+package com.usoftchina.smartschool.file.storage;
+
+/**
+ * @author yingp
+ * @date 2019/3/14
+ */
+public class FileMetadata {
+    private String mime;
+    private String ext;
+    private long size;
+
+    public FileMetadata() {
+    }
+
+    public FileMetadata(String mime, String ext, long size) {
+        this.mime = mime;
+        this.ext = ext;
+        this.size = size;
+    }
+
+    public String getMime() {
+        return mime;
+    }
+
+    public void setMime(String mime) {
+        this.mime = mime;
+    }
+
+    public String getExt() {
+        return ext;
+    }
+
+    public void setExt(String ext) {
+        this.ext = ext;
+    }
+
+    public long getSize() {
+        return size;
+    }
+
+    public void setSize(long size) {
+        this.size = size;
+    }
+}

+ 39 - 0
base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/FileStorageClient.java

@@ -0,0 +1,39 @@
+package com.usoftchina.smartschool.file.storage;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * 文件存储标准接口
+ *
+ * @author yingp
+ * @date 2019/3/14
+ */
+public interface FileStorageClient {
+
+    /**
+     * 上传文件
+     *
+     * @param inputStream
+     * @param metadata
+     * @return
+     */
+    String uploadFile(InputStream inputStream, FileMetadata metadata);
+
+    /**
+     * 删除文件
+     *
+     * @param filePath 文件路径 / 文件唯一标志
+     */
+    void deleteFile(String filePath);
+
+    /**
+     * 下载文件
+     *
+     * @param filePath 文件路径 / 文件唯一标志
+     * @param out
+     * @throws IOException
+     */
+    void downloadFile(String filePath, OutputStream out) throws IOException;
+}

+ 1 - 1
base-servers/file/file-server/src/main/java/com/usoftchina/smartschool/file/constant/FileType.java → base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/util/FileType.java

@@ -1,4 +1,4 @@
-package com.usoftchina.smartschool.file.constant;
+package com.usoftchina.smartschool.file.storage.util;
 
 /**
  * @author yingp

+ 3 - 6
base-servers/file/file-server/src/main/java/com/usoftchina/smartschool/file/util/FileTypeUtils.java → base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/util/FileTypeUtils.java

@@ -1,7 +1,4 @@
-package com.usoftchina.smartschool.file.util;
-
-import com.usoftchina.smartschool.file.constant.FileType;
-import com.usoftchina.smartschool.utils.StringUtils;
+package com.usoftchina.smartschool.file.storage.util;
 
 /**
  * @author yingp
@@ -25,7 +22,7 @@ public class FileTypeUtils {
     }
 
     public static FileType getFileTypeByMime(String mime) {
-        if (!StringUtils.isEmpty(mime)) {
+        if (null != mime && !mime.isEmpty()) {
             if (mime.startsWith("image/")) {
                 return FileType.IMAGE;
             }
@@ -56,7 +53,7 @@ public class FileTypeUtils {
     }
 
     public static FileType getFileTypeByExtension(String ext) {
-        if (!StringUtils.isEmpty(ext)) {
+        if (null != ext && !ext.isEmpty()) {
             switch (ext) {
                 case "gif":
                 case "jpeg":

+ 97 - 0
base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/util/FilenameUtils.java

@@ -0,0 +1,97 @@
+package com.usoftchina.smartschool.file.storage.util;
+
+/**
+ * @author yingp
+ * @date 2019/3/14
+ */
+public class FilenameUtils {
+
+    /**
+     * The extension separator character.
+     * @since 1.4
+     */
+    public static final char EXTENSION_SEPARATOR = '.';
+
+    /**
+     * The Unix separator character.
+     */
+    private static final char UNIX_SEPARATOR = '/';
+
+    /**
+     * The Windows separator character.
+     */
+    private static final char WINDOWS_SEPARATOR = '\\';
+
+    /**
+     * Gets the extension of a filename.
+     * <p>
+     * This method returns the textual part of the filename after the last dot.
+     * There must be no directory separator after the dot.
+     * <pre>
+     * foo.txt      --> "txt"
+     * a/b/c.jpg    --> "jpg"
+     * a/b.txt/c    --> ""
+     * a/b/c        --> ""
+     * </pre>
+     * <p>
+     * The output will be the same irrespective of the machine that the code is running on.
+     *
+     * @param filename the filename to retrieve the extension of.
+     * @return the extension of the file or an empty string if none exists or {@code null}
+     * if the filename is {@code null}.
+     */
+    public static String getExtension(String filename) {
+        if (filename == null) {
+            return null;
+        }
+        int index = indexOfExtension(filename);
+        if (index == -1) {
+            return "";
+        } else {
+            return filename.substring(index + 1);
+        }
+    }
+
+    /**
+     * Returns the index of the last extension separator character, which is a dot.
+     * <p>
+     * This method also checks that there is no directory separator after the last dot.
+     * To do this it uses {@link #indexOfLastSeparator(String)} which will
+     * handle a file in either Unix or Windows format.
+     * <p>
+     * The output will be the same irrespective of the machine that the code is running on.
+     *
+     * @param filename  the filename to find the last path separator in, null returns -1
+     * @return the index of the last separator character, or -1 if there
+     * is no such character
+     */
+    public static int indexOfExtension(String filename) {
+        if (filename == null) {
+            return -1;
+        }
+        int extensionPos = filename.lastIndexOf(EXTENSION_SEPARATOR);
+        int lastSeparator = indexOfLastSeparator(filename);
+        return lastSeparator > extensionPos ? -1 : extensionPos;
+    }
+
+    /**
+     * Returns the index of the last directory separator character.
+     * <p>
+     * This method will handle a file in either Unix or Windows format.
+     * The position of the last forward or backslash is returned.
+     * <p>
+     * The output will be the same irrespective of the machine that the code is running on.
+     *
+     * @param filename  the filename to find the last path separator in, null returns -1
+     * @return the index of the last separator character, or -1 if there
+     * is no such character
+     */
+    public static int indexOfLastSeparator(String filename) {
+        if (filename == null) {
+            return -1;
+        }
+        int lastUnixPos = filename.lastIndexOf(UNIX_SEPARATOR);
+        int lastWindowsPos = filename.lastIndexOf(WINDOWS_SEPARATOR);
+        return Math.max(lastUnixPos, lastWindowsPos);
+    }
+}

+ 5 - 0
base-servers/file/pom.xml

@@ -15,6 +15,11 @@
         <module>file-api</module>
         <module>file-dto</module>
         <module>file-server</module>
+        <module>file-server-qcloud</module>
+        <module>file-storage-fdfs</module>
+        <module>file-storage-qcloud</module>
+        <module>file-storage</module>
+        <module>file-server-fdfs</module>
     </modules>
 
 

+ 20 - 0
pom.xml

@@ -283,6 +283,26 @@
                 <artifactId>device-sdk-dahua</artifactId>
                 <version>${project.release.version}</version>
             </dependency>
+            <dependency>
+                <groupId>com.usoftchina.smartschool</groupId>
+                <artifactId>file-server</artifactId>
+                <version>${project.release.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.usoftchina.smartschool</groupId>
+                <artifactId>file-storage</artifactId>
+                <version>${project.release.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.usoftchina.smartschool</groupId>
+                <artifactId>file-storage-fdfs</artifactId>
+                <version>${project.release.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.usoftchina.smartschool</groupId>
+                <artifactId>file-storage-qcloud</artifactId>
+                <version>${project.release.version}</version>
+            </dependency>
             <!-- file upload -->
             <dependency>
                 <groupId>io.github.openfeign.form</groupId>