Переглянути джерело

中申报表list页面后端代码

user5 3 роки тому
батько
коміт
5b9908b000
17 змінених файлів з 3206 додано та 15 видалено
  1. 169 0
      jeeplus-module/jeeplus-test/src/main/java/com/jeeplus/test/reimbursementsys/controller/ReimbursementSysController.java
  2. 165 0
      jeeplus-module/jeeplus-test/src/main/java/com/jeeplus/test/reimbursementsys/domain/dto/ReimbursementDTO.java
  3. 127 0
      jeeplus-module/jeeplus-test/src/main/java/com/jeeplus/test/reimbursementsys/mapper/ReimbursementSysMapper.java
  4. 308 0
      jeeplus-module/jeeplus-test/src/main/java/com/jeeplus/test/reimbursementsys/mapper/xml/ReimbursementSysMapper.xml
  5. 69 0
      jeeplus-module/jeeplus-test/src/main/java/com/jeeplus/test/reimbursementsys/service/ReimbursementSysService.java
  6. 341 0
      jeeplus-module/jeeplus-test/src/main/java/com/jeeplus/test/reimbursementsys/service/impl/ReimbursementSysServiceImpl.java
  7. 8 0
      jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/core/domain/BaseEntity.java
  8. 31 0
      jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/core/domain/TreeEntity.java
  9. 151 0
      jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/Encodes.java
  10. 71 0
      jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/ExcelField.java
  11. 71 0
      jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/Exceptions.java
  12. 63 0
      jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/IdGen.java
  13. 412 0
      jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/ImportExcel.java
  14. 299 0
      jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/Reflections.java
  15. 86 0
      jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/SpringContextHolder.java
  16. 805 0
      jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/StringUtils.java
  17. 30 15
      pom.xml

+ 169 - 0
jeeplus-module/jeeplus-test/src/main/java/com/jeeplus/test/reimbursementsys/controller/ReimbursementSysController.java

@@ -0,0 +1,169 @@
+package com.jeeplus.test.reimbursementsys.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.google.common.collect.Lists;
+import com.jeeplus.aop.demo.annotation.DemoMode;
+import com.jeeplus.aop.logging.annotation.ApiLog;
+import com.jeeplus.sys.service.dto.LogDTO;
+import com.jeeplus.sys.service.dto.OfficeDTO;
+import com.jeeplus.sys.utils.ImportExcel;
+import com.jeeplus.sys.utils.StringUtils;
+import com.jeeplus.test.reimbursementsys.domain.dto.ReimbursementDTO;
+import com.jeeplus.test.reimbursementsys.service.ReimbursementSysService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.validation.Valid;
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * @author li-peike
+ * @version 1.0.0
+ * @ClassName ReimbursementSysController.java
+ * @Description TODO 发票信息
+ * @createTime 2022年05月05日 20:41:00
+ */
+@RestController
+@RequestMapping("/reimbursement")
+public class ReimbursementSysController {
+
+    @Autowired
+    private ReimbursementSysService service;
+
+    /**
+     * 根据id查询部门
+     * @param id
+     * @return
+     */
+    @ApiLog("查询业务具体信息")
+    //@PreAuthorize("hasAnyAuthority('sys:office:view','sys:office:add','sys:office:edit')")
+    @GetMapping("queryBusinessById")
+    public ResponseEntity queryBusinessById(@RequestParam String id) {
+        ReimbursementDTO reimbursementDTO = service.queryBusinessById (id);
+        return ResponseEntity.ok (reimbursementDTO);
+    }
+    /**
+     * 根据id查询部门
+     * @param id
+     * @return
+     */
+    @ApiLog("查询发票具体信息")
+    //@PreAuthorize("hasAnyAuthority('sys:office:view','sys:office:add','sys:office:edit')")
+    @GetMapping("queryInvoiceById")
+    public ResponseEntity queryInvoiceById(@RequestParam String id) {
+        ReimbursementDTO reimbursementDTO = service.queryInvoiceById (id);
+        return ResponseEntity.ok (reimbursementDTO);
+    }
+
+
+    /**
+     * 查询报销信息
+     * @return
+     */
+    @ApiLog("查询业务报销信息")
+    @GetMapping("treeData")
+    public ResponseEntity treeData(ReimbursementDTO reimbursementDTO,  Page<ReimbursementDTO> page) {
+        IPage<ReimbursementDTO> list = service.treeData(page,reimbursementDTO);
+        return ResponseEntity.ok(list);
+    }
+
+    /**
+     * 上传文件
+     * @return
+     * @throws IOException
+     */
+    @ApiLog("上传文件")
+    @RequestMapping("uploadFile")
+    public Map<String,Object> uploadFile(HttpServletRequest request, MultipartFile file) {
+        Map<String,Object> map = new HashMap<>();
+        try {
+            ImportExcel ei = new ImportExcel(file, 0, 0);
+            List<ReimbursementDTO> list = ei.getDataList(ReimbursementDTO.class);
+            map = service.save(list);
+            return map;
+        } catch (Exception e) {
+            map.put("message", "文件上传失败。失败原因:"+ e.getMessage());
+            map.put("success", false);
+            return map;
+        }
+    }
+
+
+    /**
+     * 保存业务报销编码
+     * @return
+     */
+    @ApiLog("保存业务报销编码")
+    @PostMapping("saveBusiness")
+    public ResponseEntity saveBusiness(@Valid @RequestBody ReimbursementDTO reimbursementDTO) {
+        if(StringUtils.isBlank(reimbursementDTO.getBusinessCode())){
+            return ResponseEntity.badRequest ().body ("业务编码不可为空,请重新填写!");
+        }
+        service.saveBusiness(reimbursementDTO);
+        return ResponseEntity.ok("保存业务编码" + reimbursementDTO.getBusinessCode() + "成功");
+    }
+
+
+    /**
+     * 保存发票收款时间
+     * @return
+     */
+    @ApiLog("保存发票收款时间")
+    @PostMapping("saveInvoice")
+    public ResponseEntity saveInvoice(@Valid @RequestBody ReimbursementDTO reimbursementDTO) {
+        service.saveInvoice(reimbursementDTO);
+        return ResponseEntity.ok("保存发票收款时间成功");
+    }
+
+    /**
+     * 批量删除
+     * @param ids
+     * @return
+     */
+    @DemoMode
+    @ApiLog("批量删除")
+    //@PreAuthorize("hasAuthority('sys:office:del')")
+    @DeleteMapping("delete")
+    public ResponseEntity delete(String ids) {
+        String idArray[] =ids.split(",");
+        service.removeBusinessByIds ( Lists.newArrayList (idArray) );
+        return ResponseEntity.ok ("删除成功!");
+    }
+
+    /**
+     * 删除业务信息
+     * @param ids
+     * @return
+     */
+    @DemoMode
+    @ApiLog("删除业务信息")
+    //@PreAuthorize("hasAuthority('sys:office:del')")
+    @DeleteMapping("deleteBusiness")
+    public ResponseEntity deleteBusiness(String ids) {
+        String idArray[] =ids.split(",");
+        service.removeBusinessByIds ( Lists.newArrayList (idArray) );
+        return ResponseEntity.ok ("删除成功!");
+    }
+
+    /**
+     * 删除发票信息
+     * @param ids
+     * @return
+     */
+    @DemoMode
+    @ApiLog("删除发票信息")
+    //@PreAuthorize("hasAuthority('sys:office:del')")
+    @DeleteMapping("deleteInvoice")
+    public ResponseEntity deleteInvoice(String ids) {
+        String idArray[] =ids.split(",");
+        service.removeInvoiceByIds ( Lists.newArrayList (idArray) );
+        return ResponseEntity.ok ("删除成功!");
+    }
+}

+ 165 - 0
jeeplus-module/jeeplus-test/src/main/java/com/jeeplus/test/reimbursementsys/domain/dto/ReimbursementDTO.java

@@ -0,0 +1,165 @@
+package com.jeeplus.test.reimbursementsys.domain.dto;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.core.domain.TreeEntity;
+import com.jeeplus.core.service.dto.TreeDTO;
+import com.jeeplus.sys.utils.ExcelField;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 中审报表数据表
+ * @author: 徐滕
+ * @version: 2022-05-11 10:31
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@TableName("zs_reimbursement_info")
+public class ReimbursementDTO extends TreeEntity<ReimbursementDTO> {
+    private String businessCode;    //业务编号
+    private String invoiceCode;     //发票代码
+    private String invoiceNumber;   //发票号码
+    private String firmName;        //购方企业名称
+
+    @DateTimeFormat(pattern =  "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    private Date makeTime;          //开票日期
+    private String name;     //商品名称
+    private String money;       //金额
+    private String tax;         //税额
+    private String income;      //收入
+    private String proposer;        //申请人
+    private String partner;         //合伙人
+    private String businessType;    //业务类型
+    private String remarks;    //备注
+    private Integer type;    //状态
+    private List<String> idList;
+
+    @DateTimeFormat(pattern =  "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    private Date gatheringTime;     //收款日期
+
+    @ExcelField(title="业务编号", align=2, sort=12)
+    public String getBusinessCode() {
+        return businessCode;
+    }
+
+    @ExcelField(title="发票代码", align=2, sort=1)
+    public String getInvoiceCode() {
+        return invoiceCode;
+    }
+
+    @ExcelField(title="发票号码", align=2, sort=2)
+    public String getInvoiceNumber() {
+        return invoiceNumber;
+    }
+
+    @ExcelField(title="购方企业名称", align=2, sort=3)
+    public String getFirmName() {
+        return firmName;
+    }
+
+    @ExcelField(title="开票日期", align=2, sort=4)
+    public Date getMakeTime() {
+        return makeTime;
+    }
+
+    @ExcelField(title="商品名称", align=2, sort=5)
+    public String getName() {
+        return name;
+    }
+
+    @ExcelField(title="金额", align=2, sort=6)
+    public String getMoney() {
+        return money;
+    }
+
+    @ExcelField(title="税额", align=2, sort=7)
+    public String getTax() {
+        return tax;
+    }
+
+    @ExcelField(title="收入", align=2, sort=8)
+    public String getIncome() {
+        return income;
+    }
+
+    @ExcelField(title="申请人", align=2, sort=9)
+    public String getProposer() {
+        return proposer;
+    }
+
+    @ExcelField(title="合伙人", align=2, sort=10)
+    public String getPartner() {
+        return partner;
+    }
+
+    @ExcelField(title="业务类型", align=2, sort=11)
+    public String getBusinessType() {
+        return businessType;
+    }
+
+    @ExcelField(title="收款日期", align=2, sort=13)
+    public Date getGatheringTime() {
+        return gatheringTime;
+    }
+
+    public void setBusinessCode(String businessCode) {
+        this.businessCode = businessCode;
+    }
+
+    public void setInvoiceCode(String invoiceCode) {
+        this.invoiceCode = invoiceCode;
+    }
+
+    public void setInvoiceNumber(String invoiceNumber) {
+        this.invoiceNumber = invoiceNumber;
+    }
+
+    public void setFirmName(String firmName) {
+        this.firmName = firmName;
+    }
+
+    public void setMakeTime(Date makeTime) {
+        this.makeTime = makeTime;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setMoney(String money) {
+        this.money = money;
+    }
+
+    public void setTax(String tax) {
+        this.tax = tax;
+    }
+
+    public void setIncome(String income) {
+        this.income = income;
+    }
+
+    public void setProposer(String proposer) {
+        this.proposer = proposer;
+    }
+
+    public void setPartner(String partner) {
+        this.partner = partner;
+    }
+
+    public void setBusinessType(String businessType) {
+        this.businessType = businessType;
+    }
+
+    public void setGatheringTime(Date gatheringTime) {
+        this.gatheringTime = gatheringTime;
+    }
+
+}

+ 127 - 0
jeeplus-module/jeeplus-test/src/main/java/com/jeeplus/test/reimbursementsys/mapper/ReimbursementSysMapper.java

@@ -0,0 +1,127 @@
+package com.jeeplus.test.reimbursementsys.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jeeplus.test.reimbursementsys.domain.dto.ReimbursementDTO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * @author li-peike
+ * @version 1.0.0
+ * @ClassName ReimbursementSysMapper.java
+ * @Description TODO
+ * @createTime 2022年05月06日 10:40:00
+ */
+public interface ReimbursementSysMapper  extends BaseMapper<ReimbursementDTO> {
+    /**
+     * 根据条件查询数据信息
+     * @param page
+     * @param reimbursement
+     * @return
+     */
+    IPage<ReimbursementDTO> queryAllList(Page<ReimbursementDTO> page, @Param("reimbursement")ReimbursementDTO reimbursement);
+
+
+    List<ReimbursementDTO> getInvoiceList(ReimbursementDTO reimbursement);
+
+    /**
+     * 根据父节点id查询发票信息
+     * @param parentIdList
+     * @return
+     */
+    List<ReimbursementDTO> getInvoiceByParentIdList(@Param("parentIdList")List<String> parentIdList);
+
+    /**
+     * 查询是否存在需要保存的发票信息
+     * @param invoiceNumberList
+     * @return
+     */
+    List<String> selectOldInvoiceNumber(@Param("invoiceNumberList") List<String> invoiceNumberList);
+
+    /**
+     * 查询是否存在已有的业务编号信息
+     * @param businessCodeList
+     * @return
+     */
+    List<String> selectOldBusinessCode(@Param("businessCodeList") List<String> businessCodeList);
+
+    /**
+     * 保存业务编号信息
+     * @param businessCodeList
+     */
+    void insertBusinessCodeList(@Param("businessCodeList")List<ReimbursementDTO> businessCodeList);
+
+    /**
+     * 保存发票编号数据信息
+     * @param invoiceInfoList
+     */
+    void insertInvoiceList(@Param("invoiceInfoList")List<ReimbursementDTO> invoiceInfoList);
+
+    /**
+     * 查询业务信息
+     * @param id
+     * @return
+     */
+    ReimbursementDTO queryBusinessById(String id);
+
+    /**
+     * 查询发票信息
+     * @param id
+     * @return
+     */
+    ReimbursementDTO queryInvoiceById(String id);
+
+    /**
+     * 保存业务编码
+     * @param reimbursement
+     * @return
+     */
+    Integer saveBusiness(ReimbursementDTO reimbursement);
+
+    /**
+     * 保存发票收款时间
+     * @param reimbursement
+     * @return
+     */
+    Integer saveInvoice(ReimbursementDTO reimbursement);
+
+    /**
+     * 根据业务编码查询业务信息
+     * @param businessCode
+     * @return
+     */
+    ReimbursementDTO getInfoByBusinessCode(String businessCode);
+
+    /**
+     * 批量修改发票信息
+     * @param invoiceInfoList
+     */
+    void updateInvoiceList(@Param("invoiceInfoList")List<ReimbursementDTO> invoiceInfoList);
+
+    /**
+     * 根据id删除对应业务信息(物理删除)
+     * @param id
+     */
+    void deleteBusinessById(String id);
+
+    /**
+     * 删除业务信息(逻辑删除)
+     * @param idList
+     */
+    void removeBusinessByIds(@Param("idList")List<String> idList);
+
+    /**
+     * 删除发票信息(逻辑删除)
+     * @param idList
+     */
+    void removeBusinessByParentIds(@Param("idList")List<String> idList);
+
+    /**
+     * 删除发票信息(逻辑删除)
+     * @param idList
+     */
+    void removeInvoiceByIds(@Param("idList")List<String> idList);
+}

+ 308 - 0
jeeplus-module/jeeplus-test/src/main/java/com/jeeplus/test/reimbursementsys/mapper/xml/ReimbursementSysMapper.xml

@@ -0,0 +1,308 @@
+<?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.jeeplus.test.reimbursementsys.mapper.ReimbursementSysMapper">
+    <sql id="reimbursementColumns">
+        a.id AS "id",
+		a.create_by AS "createBy.id",
+		a.create_date AS "createDate",
+		a.update_by AS "updateBy.id",
+		a.update_date AS "updateDate",
+		a.remarks AS "remarks",
+		a.del_flag AS "delFlag",
+		a.parent_id AS "parent.id",
+		a.parent_id AS "parentId",
+		a.parent_ids AS "parentIds",
+        a.invoice_code AS "invoiceCode",
+        a.invoice_number AS "invoiceNumber",
+        a.firm_name AS "firmName",
+        a.make_time AS "makeTime",
+		a.name AS "name",
+        a.money AS "money",
+        a.tax AS "tax",
+        a.income AS "income",
+        a.business_code AS "businessCode",
+        a.gathering_time AS "gatheringTime",
+        a.proposer AS "proposer",
+        a.partner AS "partner",
+        a.business_type AS "businessType"
+    </sql>
+
+    <select id="queryAllList" resultType="com.jeeplus.test.reimbursementsys.domain.dto.ReimbursementDTO">
+        SELECT
+            <include refid="reimbursementColumns"/>
+        FROM zs_reimbursement_info a
+        <where>
+            a.del_flag = 0
+            <if test="reimbursement.businessCode != null and reimbursement.businessCode != ''">
+            and a.business_code like concat('%',#{reimbursement.businessCode},'%')
+            </if>
+            <if test="reimbursement.idList != null and reimbursement.idList.size>0">
+                and a.id in
+                <foreach collection="reimbursement.idList" item="id" separator="," open="(" close=")">
+                    #{id}
+                </foreach>
+            </if>
+        </where>
+        order by a.business_code
+    </select>
+
+    <select id="getInvoiceList" resultType="com.jeeplus.test.reimbursementsys.domain.dto.ReimbursementDTO">
+        SELECT
+            <include refid="reimbursementColumns"/>
+        FROM zs_reimbursement_invoice_info a
+        <where>
+            a.del_flag = 0
+            <if test="invoiceNumber != null and invoiceNumber != ''">
+                and a.invoice_number like concat('%',#{invoiceNumber},'%')
+            </if>
+        </where>
+        order by a.invoice_number
+    </select>
+
+    <select id="getInvoiceByParentIdList" resultType="com.jeeplus.test.reimbursementsys.domain.dto.ReimbursementDTO">
+        SELECT
+            <include refid="reimbursementColumns"/>
+        FROM zs_reimbursement_invoice_info a
+        <where>
+            a.del_flag = 0
+            <if test="parentIdList.size>0">
+                and a.parent_id in
+                <foreach collection="parentIdList" item="parentId" separator="," open="(" close=")">
+                    #{parentId}
+                </foreach>
+            </if>
+        </where>
+        order by a.invoice_number
+    </select>
+
+    <select id="selectOldInvoiceNumber" resultType="java.lang.String">
+        SELECT
+            a.invoice_number as "invoiceNumber"
+        FROM zs_reimbursement_invoice_info a
+        <where>
+            a.del_flag = 0
+            <if test="invoiceNumberList.size>0">
+                and a.invoice_number in
+                <foreach collection="invoiceNumberList" item="invoiceNumber" separator="," open="(" close=")">
+                    #{invoiceNumber}
+                </foreach>
+            </if>
+        </where>
+    </select>
+
+    <select id="selectOldBusinessCode" resultType="java.lang.String">
+        SELECT
+            a.business_code
+        FROM zs_reimbursement_invoice_info a
+        <where>
+            a.del_flag = 0
+            <if test="businessCodeList.size>0">
+                and a.business_code in
+                <foreach collection="businessCodeList" item="businessCode" separator="," open="(" close=")">
+                    #{businessCode}
+                </foreach>
+            </if>
+        </where>
+    </select>
+
+    <insert id="insertBusinessCodeList">
+        insert into zs_reimbursement_info (
+          id,
+          create_by,
+          create_date,
+          update_by,
+          update_date,
+          remarks,
+          del_flag,
+          parent_id,
+          parent_ids,
+          business_code
+        )
+        values
+        <foreach collection="businessCodeList" item="item" separator=",">
+            ( #{item.id},
+            #{item.createBy},
+            #{item.createDate},
+            #{item.updateBy},
+            #{item.updateDate},
+            #{item.remarks},
+            #{item.delFlag},
+            #{item.parentId},
+            #{item.parentIds},
+            #{item.businessCode}
+            )
+        </foreach>
+    </insert>
+
+    <insert id="insertInvoiceList">
+        insert into zs_reimbursement_invoice_info (
+            id,
+            create_by,
+            create_date,
+            update_by,
+            update_date,
+            remarks,
+            del_flag,
+            parent_id,
+            parent_ids,
+            invoice_code,
+            invoice_number,
+            firm_name,
+            make_time,
+            name,
+            money,
+            tax,
+            income,
+            business_code,
+            gathering_time,
+            proposer,
+            partner,
+            business_type
+        )
+        values
+        <foreach collection="invoiceInfoList" item="item" separator=",">
+            ( #{item.id},
+            #{item.createBy},
+            #{item.createDate},
+            #{item.updateBy},
+            #{item.updateDate},
+            #{item.remarks},
+            #{item.delFlag},
+            #{item.parentId},
+            #{item.parentIds},
+            #{item.invoiceCode},
+            #{item.invoiceNumber},
+            #{item.firmName},
+            #{item.makeTime},
+            #{item.name},
+            #{item.money},
+            #{item.tax},
+            #{item.income},
+            #{item.businessCode},
+            #{item.gatheringTime},
+            #{item.proposer},
+            #{item.partner},
+            #{item.businessType}
+            )
+        </foreach>
+    </insert>
+
+    <select id="queryBusinessById" resultType="com.jeeplus.test.reimbursementsys.domain.dto.ReimbursementDTO">
+        SELECT
+        <include refid="reimbursementColumns"/>
+        FROM zs_reimbursement_info a
+        <where>
+            a.del_flag = 0
+            and a.id = #{id}
+        </where>
+    </select>
+
+    <select id="queryInvoiceById" resultType="com.jeeplus.test.reimbursementsys.domain.dto.ReimbursementDTO">
+        SELECT
+        <include refid="reimbursementColumns"/>
+        FROM zs_reimbursement_invoice_info a
+        <where>
+            a.del_flag = 0
+            and a.id = #{id}
+        </where>
+    </select>
+
+    <update id="saveBusiness">
+        update zs_reimbursement_info
+        set
+            update_by = #{updateBy},
+            update_date = #{updateDate},
+            business_code = #{businessCode}
+        where
+            id = #{id} and del_flag = 0
+    </update>
+
+    <update id="saveInvoice">
+        update zs_reimbursement_invoice_info
+        set
+            update_by = #{updateBy},
+            update_date = #{updateDate},
+            gathering_time = #{gatheringTime}
+        where
+            id = #{id} and del_flag = 0
+    </update>
+
+    <select id="getInfoByBusinessCode" resultType="com.jeeplus.test.reimbursementsys.domain.dto.ReimbursementDTO">
+        SELECT
+        <include refid="reimbursementColumns"/>
+        FROM zs_reimbursement_info a
+        <where>
+            a.del_flag = 0
+            and a.business_code = #{businessCode}
+        </where>
+        limit 1;
+    </select>
+
+    <update id="updateInvoiceList">
+        <foreach collection="invoiceInfoList" item="item" index="index" open="" close="" separator=";">
+            update zs_reimbursement_invoice_info
+            <set >
+                    update_by = #{item.updateBy}
+                    ,update_date = #{item.updateDate}
+                <if test="item.businessCode != null and item.businessCode != ''">
+                    ,business_code = #{item.businessCode}
+                </if>
+                <if test="item.parentId != null and item.parentId != ''">
+                    ,parent_id = #{item.parentId}
+                </if>
+                <if test="item.parentIds != null and item.parentIds != ''">
+                    ,parent_ids = #{item.parentIds}
+                </if>
+            </set>
+            where id = #{item.id} and del_flag = 0
+        </foreach>
+    </update>
+
+    <delete id="deleteBusinessById">
+        delete from zs_reimbursement_info
+        where
+            id = #{id}
+    </delete>
+
+    <update id="removeBusinessByIds">
+        update zs_reimbursement_info
+        set
+            del_flag = 1
+        <where>
+            <if test="idList != null and idList.size>0">
+                and id in
+                <foreach collection="idList" item="id" separator="," open="(" close=")">
+                    #{id}
+                </foreach>
+            </if>
+        </where>
+    </update>
+
+    <update id="removeBusinessByParentIds">
+        update zs_reimbursement_invoice_info
+        set
+        del_flag = 1
+        <where>
+            <if test="idList != null and idList.size>0">
+                and parent_id in
+                <foreach collection="idList" item="id" separator="," open="(" close=")">
+                    #{id}
+                </foreach>
+            </if>
+        </where>
+    </update>
+
+    <update id="removeInvoiceByIds">
+        update zs_reimbursement_invoice_info
+        set
+        del_flag = 1
+        <where>
+            <if test="idList != null and idList.size>0">
+                and id in
+                <foreach collection="idList" item="id" separator="," open="(" close=")">
+                    #{id}
+                </foreach>
+            </if>
+        </where>
+    </update>
+</mapper>

+ 69 - 0
jeeplus-module/jeeplus-test/src/main/java/com/jeeplus/test/reimbursementsys/service/ReimbursementSysService.java

@@ -0,0 +1,69 @@
+package com.jeeplus.test.reimbursementsys.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jeeplus.test.reimbursementsys.domain.dto.ReimbursementDTO;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author li-peike
+ * @version 1.0.0
+ * @ClassName ReimbursementSysService.java
+ * @Description TODO
+ * @createTime 2022年05月06日 10:25:00
+ */
+
+public interface ReimbursementSysService {
+    /**
+     * 查询业务具体信息
+     * @param id
+     * @return
+     */
+    ReimbursementDTO queryBusinessById(String id);
+    /**
+     * 查询业务具体信息
+     * @param id
+     * @return
+     */
+    ReimbursementDTO queryInvoiceById(String id);
+
+    IPage<ReimbursementDTO> treeData(Page<ReimbursementDTO> page, ReimbursementDTO reimbursement);
+
+    /**
+     * 保存方法
+     * @param reimbursementList
+     */
+    Map<String,Object> save(List<ReimbursementDTO> reimbursementList);
+
+    /**
+     * 保存业务编码
+     * @param reimbursement
+     */
+    void saveBusiness(ReimbursementDTO reimbursement);
+
+    /**
+     * 保存发票收款时间
+     * @param reimbursement
+     */
+    void saveInvoice(ReimbursementDTO reimbursement);
+
+    /**
+     * 批量删除(逻辑删除)
+     * @param idList
+     */
+    void removeByIds(List <String> idList);
+
+    /**
+     * 根据业务id删除对应的业务信息以及发票信息(逻辑删除)
+     * @param idList
+     */
+    void removeBusinessByIds(List <String> idList);
+
+    /**
+     * 根据发票id删除发票信息(逻辑删除)
+     * @param idList
+     */
+    void removeInvoiceByIds(List <String> idList);
+}

+ 341 - 0
jeeplus-module/jeeplus-test/src/main/java/com/jeeplus/test/reimbursementsys/service/impl/ReimbursementSysServiceImpl.java

@@ -0,0 +1,341 @@
+package com.jeeplus.test.reimbursementsys.service.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.google.common.collect.Lists;
+import com.jeeplus.sys.utils.StringUtils;
+import com.jeeplus.test.reimbursementsys.domain.dto.ReimbursementDTO;
+import com.jeeplus.test.reimbursementsys.mapper.ReimbursementSysMapper;
+import com.jeeplus.test.reimbursementsys.service.ReimbursementSysService;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.*;
+
+/**
+ * @author li-peike
+ * @version 1.0.0
+ * @ClassName ReimbursementSysServiceImpl.java
+ * @Description TODO
+ * @createTime 2022年05月06日 10:38:00
+ */
+@Service
+public class ReimbursementSysServiceImpl implements ReimbursementSysService {
+
+    @Resource
+    private ReimbursementSysMapper mapper;
+
+
+    @Override
+    public ReimbursementDTO queryBusinessById(String id) {
+        return mapper.queryBusinessById(id);
+    }
+
+    @Override
+    public ReimbursementDTO queryInvoiceById(String id) {
+        return mapper.queryInvoiceById(id);
+    }
+
+
+    @Override
+    public IPage<ReimbursementDTO> treeData(Page<ReimbursementDTO> page, ReimbursementDTO reimbursement) {
+        IPage<ReimbursementDTO> pageList = new Page();
+        //如果筛选项含有发票号码,则需先查询对应的发票信息
+        if(StringUtils.isNotBlank(reimbursement.getInvoiceNumber())){
+            List<ReimbursementDTO> invoiceList =  mapper.getInvoiceList(reimbursement);
+            //如果存在发票信息,则根据发票的父节点查询对应的业务信息
+            if(invoiceList.size()>0){
+                Set<String> idSet = new HashSet<String>();
+                for (ReimbursementDTO  info : invoiceList) {
+                    idSet.add(info.getParentId());
+                }
+                reimbursement.setIdList(new ArrayList<>(idSet));
+                pageList = mapper.queryAllList(page,reimbursement);
+
+                List<ReimbursementDTO> list =  pageList.getRecords();
+                if(list.size()>0){
+                    //将子节点信息进行分组
+                    Map<String, List<ReimbursementDTO>> invoiceListMap = dataMessageDispose(invoiceList);
+                    //将分组后的子节点信息通过遍历的方式添加到父节点中的children中
+                    for (ReimbursementDTO info:list) {
+                        for (String key : invoiceListMap.keySet()) {
+                            if (info.getId().equals(key)) {
+                                List<ReimbursementDTO> children = invoiceListMap.get(key);
+                                info.setChildren(children);
+                            }
+                        }
+                    }
+                }
+            }else{
+                return page;
+            }
+        }else{
+            pageList = mapper.queryAllList(page,reimbursement);
+            List<ReimbursementDTO> list =  pageList.getRecords();
+            if(list.size()>0){
+                //获取所有发票信息表中的数据
+                List<String> parentIdList = Lists.newArrayList();
+                for (ReimbursementDTO info:list) {
+                    parentIdList.add(info.getId());
+                }
+                //根据查询的父节点信息查询对应的子节点信息
+                List<ReimbursementDTO> invoiceList =  mapper.getInvoiceByParentIdList(parentIdList);
+                if(invoiceList.size()>0){
+                    //将子节点信息进行分组
+                    Map<String, List<ReimbursementDTO>> invoiceListMap = dataMessageDispose(invoiceList);
+                    //将分组后的子节点信息通过遍历的方式添加到父节点中的children中
+                    for (ReimbursementDTO info:list) {
+                        for (String key : invoiceListMap.keySet()) {
+                            if (info.getId().equals(key)) {
+                                List<ReimbursementDTO> children = invoiceListMap.get(key);
+                                info.setChildren(children);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return pageList;
+    }
+
+    /**
+     * 文件数据分组
+     * @param dataList
+     * @return
+     */
+    public Map<String, List<ReimbursementDTO>> dataMessageDispose(List<ReimbursementDTO> dataList) {
+        //所有有效数据均添加到list中,下边将list中的数据根据店号和收银员的id进行分割处理
+        Map<String, List<ReimbursementDTO>> result = listGroup2Map(dataList);
+        return result;
+    }
+
+    private Map<String, List<ReimbursementDTO>> listGroup2Map(List<ReimbursementDTO> list) {
+        Map<String, List<ReimbursementDTO>> userSignSerialMap = new HashMap<>();
+        if (CollectionUtils.isNotEmpty(list)) {
+            // 分组
+            for (ReimbursementDTO vo : list) {
+                List<ReimbursementDTO> tempList = userSignSerialMap.get(vo.getParentId());
+                /*如果取不到数据,那么直接new一个空的ArrayList**/
+                if (tempList == null) {
+                    tempList = new ArrayList<>();
+                    tempList.add(vo);
+                    userSignSerialMap.put(vo.getParentId(), tempList);
+                }
+                else {
+                    /*某个vo之前已经存放过了,则直接追加数据到原来的List里**/
+                    tempList.add(vo);
+                }
+            }
+        }
+        return userSignSerialMap;
+    }
+
+    /**
+     * 保存
+     * @param reimbursementList
+     */
+    @Override
+    public Map<String,Object> save(List<ReimbursementDTO> reimbursementList) {
+        Map<String,Object> map = new HashMap<>();
+        Set<String> invoiceNumberSet = new HashSet<String>();
+        for (ReimbursementDTO info : reimbursementList) {
+            if(StringUtils.isBlank(info.getBusinessCode())){
+                info.setBusinessCode("");
+            }
+            invoiceNumberSet.add(info.getInvoiceNumber());
+        }
+        //如果发票编号数量不等于总数量,则表示所传数据中存在重复的发票编号,则进行抛出
+        if(invoiceNumberSet.size() != reimbursementList.size()){
+            map.put("success", false);
+            map.put("message", "数据中存在相同的发票号,请重新验证上传");
+            return map;
+        }
+        //set转list
+        List<String> invoiceNumberList = new ArrayList<String>(invoiceNumberSet);
+        //查询发票号是否存在,若含有已存在发票号,则直接进行抛出
+        List<String> oldInvoiceNumberList = mapper.selectOldInvoiceNumber(invoiceNumberList);
+        if(oldInvoiceNumberList.size()>0){
+            String oldInvoiceNumber = String.join(",", oldInvoiceNumberList);
+            map.put("success", false);
+            map.put("message", "发票号码:" + oldInvoiceNumber + " 已存在。无法再次上传");
+            return map;
+        }
+
+        //业务编号对应的数据集合
+        List<ReimbursementDTO> businessCodeInfoList = Lists.newArrayList();
+        List<ReimbursementDTO> businessCodeNullList = Lists.newArrayList();
+        List<String> businessCodeList = Lists.newArrayList();
+        //循环遍历reimbursementList 整理出相同的业务编号(null或者空字符串除外),并将这些业务编号进行去重,保存到数据库
+        Map<String, List<ReimbursementDTO>> businessCodeListMap = dataDisposeOnSaveByBusinessCode(reimbursementList);
+        for (String key : businessCodeListMap.keySet()) {
+            if("".equals(key)){
+                List<ReimbursementDTO> infoList = businessCodeListMap.get(key);
+                businessCodeNullList.addAll(infoList);
+            }else{
+                List<ReimbursementDTO> infoList = businessCodeListMap.get(key);
+                businessCodeInfoList.add(infoList.get(0));
+                businessCodeList.add(key);
+            }
+        }
+
+        //查询非空的业务编号数据在数据库中是否存在,若存在,返回已存在的业务编号集合
+        List<String> oldBusinessCodeList = mapper.selectOldBusinessCode(businessCodeList);
+        if (oldBusinessCodeList.size()>0){
+            //如果数据库已存在部分业务编号信息,则去除该部分的业务编号信息
+            for (String oldBusinessCode: oldBusinessCodeList) {
+                Iterator iterator = businessCodeInfoList.iterator();
+                while (iterator.hasNext()) {
+                    ReimbursementDTO data = (ReimbursementDTO) iterator.next();
+                    if (oldBusinessCode.equals(data.getBusinessCode())){
+                        iterator.remove();
+                    }
+                }
+            }
+
+        }
+
+        //将空的业务编号 的信息添加到集合中
+        businessCodeInfoList.addAll(businessCodeNullList);
+        //对业务编号的数据进行新增保存
+        for (ReimbursementDTO newBusinessCodeInfo : businessCodeInfoList) {
+            newBusinessCodeInfo.preInsert();
+            newBusinessCodeInfo.setParentId("0");
+            newBusinessCodeInfo.setParentIds("0,");
+        }
+        mapper.insertBusinessCodeList(businessCodeInfoList);
+
+
+        //业务编号对应的数据集合
+        List<ReimbursementDTO> invoiceInfoList = Lists.newArrayList();
+
+        for (ReimbursementDTO info : businessCodeInfoList) {
+            if(StringUtils.isNotBlank(info.getBusinessCode())){
+                //处理业务编号不为空的数据
+                for (String key : businessCodeListMap.keySet()) {
+                    if(info.getBusinessCode().equals(key)){
+                        List<ReimbursementDTO> infoList = businessCodeListMap.get(key);
+                        for (ReimbursementDTO childrenInfo : infoList) {
+                            if(info.getBusinessCode().equals("2021-01768")){
+                                System.out.println("");
+                            }
+                            childrenInfo.setParentId(info.getId());
+                            String parentIds = "0," + info.getId() + ",";
+                            childrenInfo.setParentIds(parentIds);
+                            //childrenInfo.preInsert();
+                            invoiceInfoList.add(childrenInfo);
+                        }
+                    }
+                }
+
+            }else{
+                //处理业务编号为空的数据
+                info.setParentId(info.getId());
+                String parentIds = "0," + info.getId() + ",";
+                info.setParentIds(parentIds);
+                //info.preInsert();
+                invoiceInfoList.add(info);
+            }
+        }
+        for (ReimbursementDTO childrenInfo : invoiceInfoList) {
+            childrenInfo.preInsert();
+        }
+        //新增
+        mapper.insertInvoiceList(invoiceInfoList);
+
+        map.put("success", true);
+        map.put("message", "数据上传成功");
+        return map;
+    }
+
+    @Override
+    public void saveBusiness(ReimbursementDTO reimbursement) {
+        //查询该业务编码在数据库中是否存在
+        ReimbursementDTO infoByBusinessCode = mapper.getInfoByBusinessCode(reimbursement.getBusinessCode());
+        if(null != infoByBusinessCode){
+            //如果存在该业务编码 则将该业务编码对应的发票数据的父节点变更为已存在的业务编码的id信息
+            //根据id 查询对应的发票信息
+            List<String> parentIdList = Lists.newArrayList();
+            parentIdList.add(reimbursement.getId());
+            List<ReimbursementDTO> invoiceByParentIdList = mapper.getInvoiceByParentIdList(parentIdList);
+            if(invoiceByParentIdList.size()>0){
+                List<ReimbursementDTO> updateInvoiceData = Lists.newArrayList();
+                for (ReimbursementDTO invoiceInfo: invoiceByParentIdList) {
+                    invoiceInfo.setBusinessCode(infoByBusinessCode.getBusinessCode());
+                    invoiceInfo.setParentId(infoByBusinessCode.getId());
+                    invoiceInfo.setParentIds("0," + infoByBusinessCode.getId() + ",");
+                    invoiceInfo.preUpdate();
+                    updateInvoiceData.add(invoiceInfo);
+                }
+                mapper.updateInvoiceList(updateInvoiceData);
+            }
+            //删除该业务编码信息
+            mapper.deleteBusinessById(reimbursement.getId());
+        }else{
+            reimbursement.preUpdate();
+            mapper.saveBusiness(reimbursement);
+        }
+    }
+
+    @Override
+    public void saveInvoice(ReimbursementDTO reimbursement) {
+        reimbursement.preUpdate();
+        mapper.saveInvoice(reimbursement);
+    }
+
+    @Override
+    public void removeByIds(List<String> idList) {
+        //删除业务信息
+        mapper.removeBusinessByIds(idList);
+        //删除发票信息
+        mapper.removeInvoiceByIds(idList);
+    }
+
+    @Override
+    public void removeBusinessByIds(List<String> idList) {
+        //删除业务信息
+        mapper.removeBusinessByIds(idList);
+        //删除发票信息
+        mapper.removeBusinessByParentIds(idList);
+
+    }
+
+    @Override
+    public void removeInvoiceByIds(List<String> idList) {
+        //删除发票信息
+        mapper.removeInvoiceByIds(idList);
+    }
+
+    /**
+     * 文件数据分组
+     * @param dataList
+     * @return
+     */
+    public Map<String, List<ReimbursementDTO>> dataDisposeOnSaveByBusinessCode(List<ReimbursementDTO> dataList) {
+        Map<String, List<ReimbursementDTO>> result = listMapOnSaveByBusinessCode(dataList);
+        return result;
+    }
+
+    private Map<String, List<ReimbursementDTO>> listMapOnSaveByBusinessCode(List<ReimbursementDTO> list) {
+        Map<String, List<ReimbursementDTO>> userSignSerialMap = new HashMap<>();
+        if (CollectionUtils.isNotEmpty(list)) {
+            // 分组
+            for (ReimbursementDTO vo : list) {
+                List<ReimbursementDTO> tempList = userSignSerialMap.get(vo.getBusinessCode());
+                /*如果取不到数据,那么直接new一个空的ArrayList**/
+                if (tempList == null) {
+                    tempList = new ArrayList<>();
+                    tempList.add(vo);
+                    userSignSerialMap.put(vo.getBusinessCode(), tempList);
+                }
+                else {
+                    /*某个vo之前已经存放过了,则直接追加数据到原来的List里**/
+                    tempList.add(vo);
+                }
+            }
+        }
+        return userSignSerialMap;
+    }
+
+}

+ 8 - 0
jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/core/domain/BaseEntity.java

@@ -73,4 +73,12 @@ public abstract class BaseEntity implements Serializable {
     }
 
 
+    /**
+     * 删除标记(0:正常;1:删除;2:审核;)
+     */
+    public static final String DEL_FLAG_NORMAL = "0";
+    public static final String DEL_FLAG_DELETE = "1";
+    public static final String DEL_FLAG_AUDIT = "2";
+
+
 }

+ 31 - 0
jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/core/domain/TreeEntity.java

@@ -4,9 +4,14 @@
 package com.jeeplus.core.domain;
 
 import com.baomidou.mybatisplus.annotation.TableField;
+import com.jeeplus.sys.service.dto.UserDTO;
+import com.jeeplus.sys.utils.IdGen;
+import com.jeeplus.sys.utils.UserUtils;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
+import org.apache.commons.lang3.StringUtils;
 
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -65,4 +70,30 @@ public abstract class TreeEntity<T> extends BaseEntity {
 
 
 
+	/**
+	 * 插入之前执行方法,需要手动调用
+	 */
+	public void preInsert(){
+		setId(IdGen.uuid());
+		UserDTO user = UserUtils.getCurrentUserDTO();
+		if (StringUtils.isNotBlank(user.getId())){
+			this.setCreateBy(user.getId());
+			this.setUpdateBy(user.getId());
+		}
+		this.setCreateDate(new Date());
+		this.setUpdateDate(new Date());
+		this.setDelFlag(0);
+	}
+
+	/**
+	 * 更新之前执行方法,需要手动调用
+	 */
+	public void preUpdate(){
+		UserDTO user = UserUtils.getCurrentUserDTO();
+		if (StringUtils.isNotBlank(user.getId())){
+			this.setUpdateBy(user.getId());
+		}
+		this.setUpdateDate(new Date());
+	}
+
 }

+ 151 - 0
jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/Encodes.java

@@ -0,0 +1,151 @@
+/**
+ * Copyright (c) 2005-2012 springside.org.cn
+ */
+package com.jeeplus.sys.utils;
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.lang3.StringEscapeUtils;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+
+/**
+ * 封装各种格式的编码解码工具类.
+ * 1.Commons-Codec的 hex/base64 编码
+ * 2.自制的base62 编码
+ * 3.Commons-Lang的xml/html escape
+ * 4.JDK提供的URLEncoder
+ * @author calvin
+ * @version 2013-01-15
+ */
+public class Encodes {
+
+	private static final String DEFAULT_URL_ENCODING = "UTF-8";
+	private static final char[] BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
+
+	/**
+	 * Hex编码.
+	 */
+	public static String encodeHex(byte[] input) {
+		return new String(Hex.encodeHex(input));
+	}
+
+	/**
+	 * Hex解码.
+	 */
+	public static byte[] decodeHex(String input) {
+		try {
+			return Hex.decodeHex(input.toCharArray());
+		} catch (DecoderException e) {
+			throw Exceptions.unchecked(e);
+		}
+	}
+
+	/**
+	 * Base64编码.
+	 */
+	public static String encodeBase64(byte[] input) {
+		return new String(Base64.encodeBase64(input));
+	}
+
+	/**
+	 * Base64编码.
+	 */
+	public static String encodeBase64(String input) {
+		try {
+			return new String(Base64.encodeBase64(input.getBytes(DEFAULT_URL_ENCODING)));
+		} catch (UnsupportedEncodingException e) {
+			return "";
+		}
+	}
+
+//	/**
+//	 * Base64编码, URL安全(将Base64中的URL非法字符'+'和'/'转为'-'和'_', 见RFC3548).
+//	 */
+//	public static String encodeUrlSafeBase64(byte[] input) {
+//		return Base64.encodeBase64URLSafe(input);
+//	}
+
+	/**
+	 * Base64解码.
+	 */
+	public static byte[] decodeBase64(String input) {
+		return Base64.decodeBase64(input.getBytes());
+	}
+
+	/**
+	 * Base64解码.
+	 */
+	public static String decodeBase64String(String input) {
+		try {
+			return new String(Base64.decodeBase64(input.getBytes()), DEFAULT_URL_ENCODING);
+		} catch (UnsupportedEncodingException e) {
+			return "";
+		}
+	}
+
+	/**
+	 * Base62编码。
+	 */
+	public static String encodeBase62(byte[] input) {
+		char[] chars = new char[input.length];
+		for (int i = 0; i < input.length; i++) {
+			chars[i] = BASE62[((input[i] & 0xFF) % BASE62.length)];
+		}
+		return new String(chars);
+	}
+
+	/**
+	 * Html 转码.
+	 */
+	public static String escapeHtml(String html) {
+		return StringEscapeUtils.escapeHtml4(html);
+	}
+
+	/**
+	 * Html 解码.
+	 */
+	public static String unescapeHtml(String htmlEscaped) {
+		return StringEscapeUtils.unescapeHtml4(htmlEscaped);
+	}
+
+	/**
+	 * Xml 转码.
+	 */
+	public static String escapeXml(String xml) {
+		return StringEscapeUtils.escapeXml10(xml);
+	}
+
+	/**
+	 * Xml 解码.
+	 */
+	public static String unescapeXml(String xmlEscaped) {
+		return StringEscapeUtils.unescapeXml(xmlEscaped);
+	}
+
+	/**
+	 * URL 编码, Encode默认为UTF-8.
+	 */
+	public static String urlEncode(String part) {
+		try {
+			return URLEncoder.encode(part, DEFAULT_URL_ENCODING);
+		} catch (UnsupportedEncodingException e) {
+			throw Exceptions.unchecked(e);
+		}
+	}
+
+	/**
+	 * URL 解码, Encode默认为UTF-8. 
+	 */
+	public static String urlDecode(String part) {
+
+		try {
+			return URLDecoder.decode(part, DEFAULT_URL_ENCODING);
+		} catch (UnsupportedEncodingException e) {
+			throw Exceptions.unchecked(e);
+		}
+	}
+}

+ 71 - 0
jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/ExcelField.java

@@ -0,0 +1,71 @@
+/**
+ * Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
+ */
+package com.jeeplus.sys.utils;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Excel注解定义
+ * @author jeeplus
+ * @version 2013-03-10
+ */
+@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExcelField {
+
+	/**
+	 * 导出字段名(默认调用当前字段的“get”方法,如指定导出字段为对象,请填写“对象名.对象属性”,例:“area.name”、“office.name”)
+	 */
+	String value() default "";
+	
+	/**
+	 * 导出字段标题(需要添加批注请用“**”分隔,标题**批注,仅对导出模板有效)
+	 */
+	String title();
+	
+	/**
+	 * 字段类型(0:导出导入;1:仅导出;2:仅导入)
+	 */
+	int type() default 0;
+
+	/**
+	 * 导出字段对齐方式(0:自动;1:靠左;2:居中;3:靠右)
+	 */
+	int align() default 0;
+	
+	/**
+	 * 导出字段字段排序(升序)
+	 */
+	int sort() default 0;
+
+	/**
+	 * 如果是字典类型,请设置字典的type值
+	 */
+	String dictType() default "";
+	String mainDictType() default "";
+	
+	/**
+	 * 反射类型
+	 */
+	Class<?> fieldType() default Class.class;
+	
+	/**
+	 * 字段归属组(根据分组导出导入)
+	 */
+	int[] groups() default {};
+
+    /**
+     * 列号
+     */
+    int colNum() default 0;
+
+    /**
+     * 模板下拉--字典
+     * @return
+     */
+    String valiName() default "";
+}

+ 71 - 0
jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/Exceptions.java

@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2005-2012 springside.org.cn
+ */
+package com.jeeplus.sys.utils;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * 关于异常的工具类.
+ * @author calvin
+ * @version 2013-01-15
+ */
+public class Exceptions {
+
+	/**
+	 * 将CheckedException转换为UncheckedException.
+	 */
+	public static RuntimeException unchecked(Exception e) {
+		if (e instanceof RuntimeException) {
+			return (RuntimeException) e;
+		} else {
+			return new RuntimeException(e);
+		}
+	}
+
+	/**
+	 * 将ErrorStack转化为String.
+	 */
+	public static String getStackTraceAsString(Throwable e) {
+		if (e == null){
+			return "";
+		}
+		StringWriter stringWriter = new StringWriter();
+		e.printStackTrace(new PrintWriter(stringWriter));
+		return stringWriter.toString();
+	}
+
+	/**
+	 * 判断异常是否由某些底层的异常引起.
+	 */
+	public static boolean isCausedBy(Exception ex, Class<? extends Exception>... causeExceptionClasses) {
+		Throwable cause = ex.getCause();
+		while (cause != null) {
+			for (Class<? extends Exception> causeClass : causeExceptionClasses) {
+				if (causeClass.isInstance(cause)) {
+					return true;
+				}
+			}
+			cause = cause.getCause();
+		}
+		return false;
+	}
+
+	/**
+	 * 在request中获取异常类
+	 * @param request
+	 * @return 
+	 */
+	public static Throwable getThrowable(HttpServletRequest request){
+		Throwable ex = null;
+		if (request.getAttribute("exception") != null) {
+			ex = (Throwable) request.getAttribute("exception");
+		} else if (request.getAttribute("javax.servlet.error.exception") != null) {
+			ex = (Throwable) request.getAttribute("javax.servlet.error.exception");
+		}
+		return ex;
+	}
+	
+}

+ 63 - 0
jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/IdGen.java

@@ -0,0 +1,63 @@
+/**
+ * Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
+ */
+package com.jeeplus.sys.utils;
+
+import org.apache.shiro.session.Session;
+import org.apache.shiro.session.mgt.eis.SessionIdGenerator;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+
+import java.io.Serializable;
+import java.security.SecureRandom;
+import java.util.UUID;
+
+/**
+ * 封装各种生成唯一性ID算法的工具类.
+ * @author jeeplus
+ * @version 2016-01-15
+ */
+@Service
+@Lazy(false)
+public class IdGen implements SessionIdGenerator {
+
+	private static SecureRandom random = new SecureRandom();
+	
+	/**
+	 * 封装JDK自带的UUID, 通过Random数字生成, 中间无-分割.
+	 */
+	public static String uuid() {
+		return UUID.randomUUID().toString().replaceAll("-", "");
+	}
+	
+	/**
+	 * 使用SecureRandom随机生成Long. 
+	 */
+	public static long randomLong() {
+		return Math.abs(random.nextLong());
+	}
+
+	/**
+	 * 基于Base62编码的SecureRandom随机生成bytes.
+	 */
+	public static String randomBase62(int length) {
+		byte[] randomBytes = new byte[length];
+		random.nextBytes(randomBytes);
+		return Encodes.encodeBase62(randomBytes);
+	}
+	
+
+	@Override
+	public Serializable generateId(Session session) {
+		return IdGen.uuid();
+	}
+	
+	public static void main(String[] args) {
+		System.out.println(IdGen.uuid());
+		System.out.println(IdGen.uuid().length());
+		for (int i=0; i<1000; i++){
+			System.out.println(IdGen.randomLong() + "  " + IdGen.randomBase62(5));
+		}
+	}
+
+}

+ 412 - 0
jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/ImportExcel.java

@@ -0,0 +1,412 @@
+/**
+ * Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
+ */
+package com.jeeplus.sys.utils;
+
+import com.google.common.collect.Lists;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.hssf.usermodel.HSSFDateUtil;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.text.NumberFormat;
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 导入Excel文件(支持“XLS”和“XLSX”格式)
+ * @author jeeplus
+ * @version 2013-03-10
+ */
+public class ImportExcel {
+
+	private static Logger log = LoggerFactory.getLogger(ImportExcel.class);
+
+	/**
+	 * 工作薄对象
+	 */
+	private Workbook wb;
+
+	/**
+	 * 工作表对象
+	 */
+	private Sheet sheet;
+
+	/**
+	 * 标题行号
+	 */
+	private int headerNum;
+
+	/**
+	 * 构造函数
+	 * @param headerNum 标题行号,数据行号=标题行号+1
+	 * @throws InvalidFormatException
+	 * @throws IOException
+	 */
+	public ImportExcel(String fileName, int headerNum)
+			throws InvalidFormatException, IOException {
+		this(new File(fileName), headerNum);
+	}
+	public int sheetCirculation() {
+		int sheetCount = -1;
+		sheetCount = this.wb.getNumberOfSheets();
+		return sheetCount;
+	}
+	/**
+	 * 构造函数
+	 * @param headerNum 标题行号,数据行号=标题行号+1
+	 * @throws InvalidFormatException
+	 * @throws IOException
+	 */
+	public ImportExcel(File file, int headerNum)
+			throws InvalidFormatException, IOException {
+		this(file, headerNum, 0);
+	}
+
+	/**
+	 * 构造函数
+	 * @param headerNum 标题行号,数据行号=标题行号+1
+	 * @param sheetIndex 工作表编号
+	 * @throws InvalidFormatException
+	 * @throws IOException
+	 */
+	public ImportExcel(String fileName, int headerNum, int sheetIndex)
+			throws InvalidFormatException, IOException {
+		this(new File(fileName), headerNum, sheetIndex);
+	}
+
+	/**
+	 * 构造函数
+	 * @param headerNum 标题行号,数据行号=标题行号+1
+	 * @param sheetIndex 工作表编号
+	 * @throws InvalidFormatException
+	 * @throws IOException
+	 */
+	public ImportExcel(File file, int headerNum, int sheetIndex)
+			throws InvalidFormatException, IOException {
+		this(file.getName(), new FileInputStream(file), headerNum, sheetIndex);
+	}
+
+	/**
+	 * 构造函数
+	 * @param headerNum 标题行号,数据行号=标题行号+1
+	 * @param sheetIndex 工作表编号
+	 * @throws InvalidFormatException
+	 * @throws IOException
+	 */
+	public ImportExcel(MultipartFile multipartFile, int headerNum, int sheetIndex)
+			throws InvalidFormatException, IOException {
+		this(multipartFile.getOriginalFilename(), multipartFile.getInputStream(), headerNum, sheetIndex);
+	}
+
+	/**
+	 * 构造函数
+	 * @param headerNum 标题行号,数据行号=标题行号+1
+	 * @param sheetIndex 工作表编号
+	 * @throws InvalidFormatException
+	 * @throws IOException
+	 */
+	public ImportExcel(String fileName, InputStream is, int headerNum, int sheetIndex)
+			throws InvalidFormatException, IOException {
+		if (StringUtils.isBlank(fileName)){
+			throw new RuntimeException("导入文档为空!");
+		}else if(fileName.toLowerCase().endsWith("xls")){
+			this.wb = new HSSFWorkbook(is);
+        }else if(fileName.toLowerCase().endsWith("xlsx")){
+        	this.wb = new XSSFWorkbook(is);
+        }else{
+        	throw new RuntimeException("文档格式不正确!");
+        }
+		if (this.wb.getNumberOfSheets()<sheetIndex){
+			throw new RuntimeException("文档中没有工作表!");
+		}
+		this.sheet = this.wb.getSheetAt(sheetIndex);
+		this.headerNum = headerNum;
+		log.debug("Initialize success.");
+	}
+
+	/**
+	 * 获取行对象
+	 * @param rownum
+	 * @return
+	 */
+	public Row getRow(int rownum){
+		return this.sheet.getRow(rownum);
+	}
+	/**
+	 * header内容
+	 * @param
+	 * @return
+	 */
+	public String getHeaderStr(){
+		return this.sheet.getSheetName();
+	}
+	/**
+	 * 获取数据行号
+	 * @return
+	 */
+	public int getDataRowNum(){
+		return headerNum+1;
+	}
+
+	/**
+	 * 获取最后一个数据行号
+	 * @return
+	 */
+	public int getLastDataRowNum(){
+		return this.sheet.getLastRowNum()+headerNum;
+	}
+
+	/**
+	 * 获取最后一个列号
+	 * @return
+	 */
+	public int getLastCellNum(){
+		return this.getRow(headerNum).getLastCellNum();
+	}
+
+	/**
+	 * 获取单元格值
+	 * @param row 获取的行
+	 * @param column 获取单元格列号
+	 * @return 单元格值
+	 */
+	public Object getCellValue(Row row, int column) {
+		Object val = "";
+		try {
+			Cell cell = row.getCell(column);
+
+			if (cell != null) {
+				if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
+					// val = cell.getNumericCellValue();
+					// 当excel 中的数据为数值或日期是需要特殊处理
+					if (HSSFDateUtil.isCellDateFormatted(cell)) {
+						double d = cell.getNumericCellValue();
+						Date date = HSSFDateUtil.getJavaDate(d);
+						SimpleDateFormat dformat = new SimpleDateFormat(
+								"yyyy-MM-dd");
+						val = dformat.format(date);
+					} else {
+						NumberFormat nf = NumberFormat.getInstance();
+						nf.setGroupingUsed(false);// true时的格式:1,234,567,890
+						val = nf.format(cell.getNumericCellValue());// 数值类型的数据为double,所以需要转换一下
+                        if(((String) val).contains(",")){
+                            val = nf.parse(val.toString()).doubleValue();
+                        }
+					}
+				} else if (cell.getCellType() == Cell.CELL_TYPE_STRING) {
+					val = replaceBlank(cell.getStringCellValue());
+				} else if (cell.getCellType() == Cell.CELL_TYPE_FORMULA) {
+					//val = cell.getCellFormula();
+					try {
+						val = String.valueOf(cell.getNumericCellValue());
+						if(String.valueOf(cell.getNumericCellValue()).indexOf("E")==-1){
+							val= String.valueOf(cell.getNumericCellValue());
+						}else {
+							NumberFormat formatter=NumberFormat.getNumberInstance();
+							formatter.setMinimumFractionDigits(4);
+							val=formatter.format(cell.getNumericCellValue());
+                            if(((String) val).contains(",")){
+                              val= val.toString().replaceAll(",","");
+                            }
+						}
+
+						 } catch (IllegalStateException e) {
+						val = String.valueOf(cell.getRichStringCellValue());
+						 }
+				} else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
+					val = cell.getBooleanCellValue();
+				} else if (cell.getCellType() == Cell.CELL_TYPE_ERROR) {
+					val = cell.getErrorCellValue();
+				}
+			}
+		} catch (Exception e) {
+			return val;
+		}
+		return val;
+	}
+
+	/**
+	 * 获取导入数据列表
+	 * @param cls 导入对象类型
+	 * @param groups 导入分组
+	 */
+	public <E> List<E> getDataList(Class<E> cls, int... groups) throws InstantiationException, IllegalAccessException{
+		List<Object[]> annotationList = Lists.newArrayList();
+		// Get annotation field
+		Field[] fs = cls.getDeclaredFields();
+		for (Field f : fs){
+			ExcelField ef = f.getAnnotation(ExcelField.class);
+			if (ef != null && (ef.type()==0 || ef.type()==2)){
+				if (groups!=null && groups.length>0){
+					boolean inGroup = false;
+					for (int g : groups){
+						if (inGroup){
+							break;
+						}
+						for (int efg : ef.groups()){
+							if (g == efg){
+								inGroup = true;
+								annotationList.add(new Object[]{ef, f});
+								break;
+							}
+						}
+					}
+				}else{
+					annotationList.add(new Object[]{ef, f});
+				}
+			}
+		}
+		// Get annotation method
+		Method[] ms = cls.getDeclaredMethods();
+		for (Method m : ms){
+			ExcelField ef = m.getAnnotation(ExcelField.class);
+			if (ef != null && (ef.type()==0 || ef.type()==2)){
+				if (groups!=null && groups.length>0){
+					boolean inGroup = false;
+					for (int g : groups){
+						if (inGroup){
+							break;
+						}
+						for (int efg : ef.groups()){
+							if (g == efg){
+								inGroup = true;
+								annotationList.add(new Object[]{ef, m});
+								break;
+							}
+						}
+					}
+				}else{
+					annotationList.add(new Object[]{ef, m});
+				}
+			}
+		}
+		// Field sorting
+		Collections.sort(annotationList, new Comparator<Object[]>() {
+			public int compare(Object[] o1, Object[] o2) {
+				return new Integer(((ExcelField)o1[0]).sort()).compareTo(
+						new Integer(((ExcelField)o2[0]).sort()));
+			};
+		});
+		//log.debug("Import column count:"+annotationList.size());
+		// Get excel data
+		List<E> dataList = Lists.newArrayList();
+		for (int i = this.getDataRowNum(); i < this.getLastDataRowNum(); i++) {
+			E e = (E)cls.newInstance();
+			int column = 0;
+			Row row = this.getRow(i);
+			StringBuilder sb = new StringBuilder();
+			for (Object[] os : annotationList){
+                ExcelField ef = (ExcelField)os[0];
+                Object val = null;
+                if (ef.colNum()!=0) {
+                    val = this.getCellValue(row, ef.colNum());
+                }else {
+                    val = this.getCellValue(row, column++);
+                }
+				if (val != null){
+
+					// If is dict type, get dict value
+					if (StringUtils.isNotBlank(ef.dictType())){
+						val = DictUtils.getDictValue(val.toString(), ef.dictType(), "");
+						//log.debug("Dictionary type value: ["+i+","+colunm+"] " + val);
+					}
+					// Get param type and type cast
+					Class<?> valType = Class.class;
+					if (os[1] instanceof Field){
+						valType = ((Field)os[1]).getType();
+					}else if (os[1] instanceof Method){
+						Method method = ((Method)os[1]);
+						if ("get".equals(method.getName().substring(0, 3))){
+							valType = method.getReturnType();
+						}else if("set".equals(method.getName().substring(0, 3))){
+							valType = ((Method)os[1]).getParameterTypes()[0];
+						}
+					}
+					//log.debug("Import value type: ["+i+","+column+"] " + valType);
+					try {
+						//如果导入的java对象,需要在这里自己进行变换。
+						if (valType == String.class){
+							String s = String.valueOf(val.toString());
+							if(StringUtils.endsWith(s, ".0")){
+								val = StringUtils.substringBefore(s, ".0");
+							}else{
+								val = String.valueOf(val.toString());
+							}
+						}else if (valType == Integer.class){
+							val = Double.valueOf(val.toString()).intValue();
+						}else if (valType == Long.class){
+							val = Double.valueOf(val.toString()).longValue();
+						}else if (valType == Double.class){
+                            if(val instanceof String){
+                                val = ((String) val).replaceAll(",","");
+                            }
+							val = Double.valueOf(val.toString());
+						}else if (valType == Float.class){
+							val = Float.valueOf(val.toString());
+						}else if (valType == Date.class){
+							SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
+							val=sdf.parse(val.toString());
+						}else{
+							if (ef.fieldType() != Class.class){
+								val = ef.fieldType().getMethod("getValue", String.class).invoke(null, val.toString());
+							}else{
+								val = Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(),
+										"fieldtype."+valType.getSimpleName()+"Type")).getMethod("getValue", String.class).invoke(null, val.toString());
+							}
+						}
+					} catch (Exception ex) {
+						log.info("Get cell value ["+i+","+column+"] error: " + ex.toString());
+						val = null;
+					}
+					// set entity value
+					if (os[1] instanceof Field){
+						Reflections.invokeSetter(e, ((Field)os[1]).getName(), val);
+					}else if (os[1] instanceof Method){
+						String mthodName = ((Method)os[1]).getName();
+						if ("get".equals(mthodName.substring(0, 3))){
+							mthodName = "set"+ StringUtils.substringAfter(mthodName, "get");
+						}
+						try {
+                            Reflections.invokeMethod(e, mthodName, new Class[]{valType}, new Object[]{val});
+                        }catch (Exception e3){
+						    log.error("解析Excel失败。",e3);
+                        }
+					}
+				}
+				sb.append(val+", ");
+			}
+			dataList.add(e);
+			log.debug("Read success: ["+i+"] "+sb.toString());
+		}
+		return dataList;
+	}
+    public static String replaceBlank(String str) {
+        String dest = "";
+        if (str!=null) {
+            Pattern p = Pattern.compile("\t|\r|\n");
+            Matcher m = p.matcher(str);
+            dest = m.replaceAll("");
+        }
+        return dest;
+    }
+}

+ 299 - 0
jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/Reflections.java

@@ -0,0 +1,299 @@
+/**
+ * Copyright (c) 2005-2012 springside.org.cn
+ */
+package com.jeeplus.sys.utils;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.Validate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.Assert;
+
+import java.lang.reflect.*;
+
+/**
+ * 反射工具类.
+ * 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
+ * @author calvin
+ * @version 2013-01-15
+ */
+@SuppressWarnings("rawtypes")
+public class Reflections {
+	
+	private static final String SETTER_PREFIX = "set";
+
+	private static final String GETTER_PREFIX = "get";
+
+	private static final String CGLIB_CLASS_SEPARATOR = "$$";
+	
+	private static Logger logger = LoggerFactory.getLogger(Reflections.class);
+
+	/**
+	 * 调用Getter方法.
+	 * 支持多级,如:对象名.对象名.方法
+	 */
+	public static Object invokeGetter(Object obj, String propertyName) {
+		Object object = obj;
+		for (String name : StringUtils.split(propertyName, ".")){
+			String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
+			object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
+		}
+		return object;
+	}
+
+	/**
+	 * 调用Setter方法, 仅匹配方法名。
+	 * 支持多级,如:对象名.对象名.方法
+	 */
+	public static void invokeSetter(Object obj, String propertyName, Object value) {
+		Object object = obj;
+		String[] names = StringUtils.split(propertyName, ".");
+		for (int i=0; i<names.length; i++){
+			if(i<names.length-1){
+				String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
+				object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
+			}else{
+				String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
+				invokeMethodByName(object, setterMethodName, new Object[] { value });
+			}
+		}
+	}
+
+	/**
+	 * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
+	 */
+	public static Object getFieldValue(final Object obj, final String fieldName) {
+		Field field = getAccessibleField(obj, fieldName);
+
+		if (field == null) {
+			throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
+		}
+
+		Object result = null;
+		try {
+			result = field.get(obj);
+		} catch (IllegalAccessException e) {
+			logger.error("不可能抛出的异常{}", e.getMessage());
+		}
+		return result;
+	}
+
+	/**
+	 * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
+	 */
+	public static void setFieldValue(final Object obj, final String fieldName, final Object value) {
+		Field field = getAccessibleField(obj, fieldName);
+
+		if (field == null) {
+			throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
+		}
+
+		try {
+			field.set(obj, value);
+		} catch (IllegalAccessException e) {
+			logger.error("不可能抛出的异常:{}", e.getMessage());
+		}
+	}
+
+	/**
+	 * 直接调用对象方法, 无视private/protected修饰符.
+	 * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
+	 * 同时匹配方法名+参数类型,
+	 */
+	public static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
+			final Object[] args) {
+		Method method = getAccessibleMethod(obj, methodName, parameterTypes);
+		if (method == null) {
+			throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
+		}
+
+		try {
+			return method.invoke(obj, args);
+		} catch (Exception e) {
+			throw convertReflectionExceptionToUnchecked(e);
+		}
+	}
+
+	/**
+	 * 直接调用对象方法, 无视private/protected修饰符,
+	 * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
+	 * 只匹配函数名,如果有多个同名函数调用第一个。
+	 */
+	public static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) {
+		Method method = getAccessibleMethodByName(obj, methodName);
+		if (method == null) {
+			throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
+		}
+
+		try {
+			return method.invoke(obj, args);
+		} catch (Exception e) {
+			throw convertReflectionExceptionToUnchecked(e);
+		}
+	}
+
+	/**
+	 * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
+	 * 
+	 * 如向上转型到Object仍无法找到, 返回null.
+	 */
+	public static Field getAccessibleField(final Object obj, final String fieldName) {
+		Validate.notNull(obj, "object can't be null");
+		Validate.notBlank(fieldName, "fieldName can't be blank");
+		for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
+			try {
+				Field field = superClass.getDeclaredField(fieldName);
+				makeAccessible(field);
+				return field;
+			} catch (NoSuchFieldException e) {//NOSONAR
+				// Field不在当前类定义,继续向上转型
+				continue;// new add
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
+	 * 如向上转型到Object仍无法找到, 返回null.
+	 * 匹配函数名+参数类型。
+	 * 
+	 * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
+	 */
+	public static Method getAccessibleMethod(final Object obj, final String methodName,
+			final Class<?>... parameterTypes) {
+		Validate.notNull(obj, "object can't be null");
+		Validate.notBlank(methodName, "methodName can't be blank");
+
+		for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
+			try {
+				Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
+				makeAccessible(method);
+				return method;
+			} catch (NoSuchMethodException e) {
+				// Method不在当前类定义,继续向上转型
+				continue;// new add
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
+	 * 如向上转型到Object仍无法找到, 返回null.
+	 * 只匹配函数名。
+	 * 
+	 * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
+	 */
+	public static Method getAccessibleMethodByName(final Object obj, final String methodName) {
+		Validate.notNull(obj, "object can't be null");
+		Validate.notBlank(methodName, "methodName can't be blank");
+
+		for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
+			Method[] methods = searchType.getDeclaredMethods();
+			for (Method method : methods) {
+				if (method.getName().equals(methodName)) {
+					makeAccessible(method);
+					return method;
+				}
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
+	 */
+	public static void makeAccessible(Method method) {
+		if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
+				&& !method.isAccessible()) {
+			method.setAccessible(true);
+		}
+	}
+
+	/**
+	 * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
+	 */
+	public static void makeAccessible(Field field) {
+		if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier
+				.isFinal(field.getModifiers())) && !field.isAccessible()) {
+			field.setAccessible(true);
+		}
+	}
+
+	/**
+	 * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
+	 * 如无法找到, 返回Object.class.
+	 * eg.
+	 * public UserDao extends HibernateDao<User>
+	 *
+	 * @param clazz The class to introspect
+	 * @return the first generic declaration, or Object.class if cannot be determined
+	 */
+	@SuppressWarnings("unchecked")
+	public static <T> Class<T> getClassGenricType(final Class clazz) {
+		return getClassGenricType(clazz, 0);
+	}
+
+	/**
+	 * 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
+	 * 如无法找到, 返回Object.class.
+	 * 
+	 * 如public UserDao extends HibernateDao<User,Long>
+	 *
+	 * @param clazz clazz The class to introspect
+	 * @param index the Index of the generic ddeclaration,start from 0.
+	 * @return the index generic declaration, or Object.class if cannot be determined
+	 */
+	public static Class getClassGenricType(final Class clazz, final int index) {
+
+		Type genType = clazz.getGenericSuperclass();
+
+		if (!(genType instanceof ParameterizedType)) {
+			logger.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
+			return Object.class;
+		}
+
+		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
+
+		if (index >= params.length || index < 0) {
+			logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
+					+ params.length);
+			return Object.class;
+		}
+		if (!(params[index] instanceof Class)) {
+			logger.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
+			return Object.class;
+		}
+
+		return (Class) params[index];
+	}
+	
+	public static Class<?> getUserClass(Object instance) {
+		Assert.notNull(instance, "Instance must not be null");
+		Class clazz = instance.getClass();
+		if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
+			Class<?> superClass = clazz.getSuperclass();
+			if (superClass != null && !Object.class.equals(superClass)) {
+				return superClass;
+			}
+		}
+		return clazz;
+
+	}
+	
+	/**
+	 * 将反射时的checked exception转换为unchecked exception.
+	 */
+	public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) {
+		if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
+				|| e instanceof NoSuchMethodException) {
+			return new IllegalArgumentException(e);
+		} else if (e instanceof InvocationTargetException) {
+			return new RuntimeException(((InvocationTargetException) e).getTargetException());
+		} else if (e instanceof RuntimeException) {
+			return (RuntimeException) e;
+		}
+		return new RuntimeException("Unexpected Checked Exception.", e);
+	}
+}

+ 86 - 0
jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/SpringContextHolder.java

@@ -0,0 +1,86 @@
+/**
+ * Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
+ */
+package com.jeeplus.sys.utils;
+
+import org.apache.commons.lang3.Validate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+
+/**
+ * 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候取出ApplicaitonContext.
+ * 
+ * @author Zaric
+ * @date 2013-5-29 下午1:25:40
+ */
+@Service
+@Lazy(false)
+public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
+
+	private static ApplicationContext applicationContext = null;
+
+	private static Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);
+
+	/**
+	 * 取得存储在静态变量中的ApplicationContext.
+	 */
+	public static ApplicationContext getApplicationContext() {
+		assertContextInjected();
+		return applicationContext;
+	}
+
+	/**
+	 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
+	 */
+	@SuppressWarnings("unchecked")
+	public static <T> T getBean(String name) {
+		assertContextInjected();
+		return (T) applicationContext.getBean(name);
+	}
+
+	/**
+	 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
+	 */
+	public static <T> T getBean(Class<T> requiredType) {
+		assertContextInjected();
+		return applicationContext.getBean(requiredType);
+	}
+
+	/**
+	 * 清除SpringContextHolder中的ApplicationContext为Null.
+	 */
+	public static void clearHolder() {
+		if (logger.isDebugEnabled()){
+			logger.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
+		}
+		applicationContext = null;
+	}
+
+	/**
+	 * 实现ApplicationContextAware接口, 注入Context到静态变量中.
+	 */
+	@Override
+	public void setApplicationContext(ApplicationContext applicationContext) {
+		SpringContextHolder.applicationContext = applicationContext;
+	}
+
+	/**
+	 * 实现DisposableBean接口, 在Context关闭时清理静态变量.
+	 */
+	@Override
+	public void destroy() throws Exception {
+		SpringContextHolder.clearHolder();
+	}
+
+	/**
+	 * 检查ApplicationContext不为空.
+	 */
+	private static void assertContextInjected() {
+		Validate.validState(applicationContext != null, "applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder.");
+	}
+}

+ 805 - 0
jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/StringUtils.java

@@ -0,0 +1,805 @@
+/**
+ * Copyright &copy; 2013-2017 <a href="http://www.rhcncpa.com/">瑞华会计师事务所</a> All rights reserved.
+ */
+package com.jeeplus.sys.utils;
+
+import com.google.common.collect.Lists;
+import net.sf.json.JSONObject;
+import net.sourceforge.pinyin4j.PinyinHelper;
+import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
+import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
+import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
+import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
+import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.springframework.web.servlet.LocaleResolver;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 字符串工具类, 继承org.apache.commons.lang3.StringUtils类
+ * @author jeeplus
+ * @version 2013-05-22
+ */
+public class StringUtils extends org.apache.commons.lang3.StringUtils {
+
+	private static final char SEPARATOR = '_';
+	private static final String CHARSET_NAME = "UTF-8";
+	private static final int DEF_DIV_SCALE = 10; //这个类不能实例化
+	public static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
+	public static SimpleDateFormat sdfs = new SimpleDateFormat("HHmm");
+
+	/**
+	 * 转换为字节数组
+	 * @param str
+	 * @return
+	 */
+	public static byte[] getBytes(String str){
+		if (str != null){
+			try {
+				return str.getBytes(CHARSET_NAME);
+			} catch (UnsupportedEncodingException e) {
+				return null;
+			}
+		}else{
+			return null;
+		}
+	}
+
+	/**
+	 * 转换为字节数组
+	 * @param bytes
+	 * @return
+	 */
+	public static String toString(byte[] bytes){
+		try {
+			return new String(bytes, CHARSET_NAME);
+		} catch (UnsupportedEncodingException e) {
+			return EMPTY;
+		}
+	}
+
+	/**
+	 * 是否包含字符串
+	 * @param str 验证字符串
+	 * @param strs 字符串组
+	 * @return 包含返回true
+	 */
+	public static boolean inString(String str, String... strs){
+		if (str != null){
+			for (String s : strs){
+				if (str.equals(trim(s))){
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * 替换掉HTML标签方法
+	 */
+	public static String replaceHtml(String html) {
+		if (isBlank(html)){
+			return "";
+		}
+		String regEx = "<.+?>";
+		Pattern p = Pattern.compile(regEx);
+		Matcher m = p.matcher(html);
+		String s = m.replaceAll("");
+		return s;
+	}
+
+	/**
+	 * 替换为手机识别的HTML,去掉样式及属性,保留回车。
+	 * @param html
+	 * @return
+	 */
+	public static String replaceMobileHtml(String html){
+		if (html == null){
+			return "";
+		}
+		return html.replaceAll("<([a-z]+?)\\s+?.*?>", "<$1>");
+	}
+
+	/**
+	 * 替换为手机识别的HTML,去掉样式及属性,保留回车。
+	 * @param txt
+	 * @return
+	 */
+	public static String toHtml(String txt){
+		if (txt == null){
+			return "";
+		}
+		return replace(replace(Encodes.escapeHtml(txt), "\n", "<br/>"), "\t", "&nbsp; &nbsp; ");
+	}
+
+	/**
+	 * 缩略字符串(不区分中英文字符)
+	 * @param str 目标字符串
+	 * @param length 截取长度
+	 * @return
+	 */
+	public static String abbr(String str, int length) {
+		if (str == null) {
+			return "";
+		}
+		try {
+			StringBuilder sb = new StringBuilder();
+			int currentLength = 0;
+			for (char c : replaceHtml(StringEscapeUtils.unescapeHtml4(str)).toCharArray()) {
+				currentLength += String.valueOf(c).getBytes("GBK").length;
+				if (currentLength <= length - 3) {
+					sb.append(c);
+				} else {
+					sb.append("...");
+					break;
+				}
+			}
+			return sb.toString();
+		} catch (UnsupportedEncodingException e) {
+			e.printStackTrace();
+		}
+		return "";
+	}
+
+	public static String abbr2(String param, int length) {
+		if (param == null) {
+			return "";
+		}
+		StringBuffer result = new StringBuffer();
+		int n = 0;
+		char temp;
+		boolean isCode = false; // 是不是HTML代码
+		boolean isHTML = false; // 是不是HTML特殊字符,如&nbsp;
+		for (int i = 0; i < param.length(); i++) {
+			temp = param.charAt(i);
+			if (temp == '<') {
+				isCode = true;
+			} else if (temp == '&') {
+				isHTML = true;
+			} else if (temp == '>' && isCode) {
+				n = n - 1;
+				isCode = false;
+			} else if (temp == ';' && isHTML) {
+				isHTML = false;
+			}
+			try {
+				if (!isCode && !isHTML) {
+					n += String.valueOf(temp).getBytes("GBK").length;
+				}
+			} catch (UnsupportedEncodingException e) {
+				e.printStackTrace();
+			}
+
+			if (n <= length - 3) {
+				result.append(temp);
+			} else {
+				result.append("...");
+				break;
+			}
+		}
+		// 取出截取字符串中的HTML标记
+		String temp_result = result.toString().replaceAll("(>)[^<>]*(<?)",
+				"$1$2");
+		// 去掉不需要结素标记的HTML标记
+		temp_result = temp_result
+				.replaceAll(
+						"</?(AREA|BASE|BASEFONT|BODY|BR|COL|COLGROUP|DD|DT|FRAME|HEAD|HR|HTML|IMG|INPUT|ISINDEX|LI|LINK|META|OPTION|P|PARAM|TBODY|TD|TFOOT|TH|THEAD|TR|area|base|basefont|body|br|col|colgroup|dd|dt|frame|head|hr|html|img|input|isindex|li|link|meta|option|p|param|tbody|td|tfoot|th|thead|tr)[^<>]*/?>",
+						"");
+		// 去掉成对的HTML标记
+		temp_result = temp_result.replaceAll("<([a-zA-Z]+)[^<>]*>(.*?)</\\1>",
+				"$2");
+		// 用正则表达式取出标记
+		Pattern p = Pattern.compile("<([a-zA-Z]+)[^<>]*>");
+		Matcher m = p.matcher(temp_result);
+		List<String> endHTML = Lists.newArrayList();
+		while (m.find()) {
+			endHTML.add(m.group(1));
+		}
+		// 补全不成对的HTML标记
+		for (int i = endHTML.size() - 1; i >= 0; i--) {
+			result.append("</");
+			result.append(endHTML.get(i));
+			result.append(">");
+		}
+		return result.toString();
+	}
+
+	/**
+	 * 转换为Double类型
+	 */
+	public static Double toDouble(Object val){
+		if (val == null){
+			return 0D;
+		}
+		try {
+			return Double.valueOf(trim(val.toString()));
+		} catch (Exception e) {
+			return 0D;
+		}
+	}
+
+	/**
+	 * 转换为Float类型
+	 */
+	public static Float toFloat(Object val){
+		return toDouble(val).floatValue();
+	}
+
+	/**
+	 * 转换为Long类型
+	 */
+	public static Long toLong(Object val){
+		return toDouble(val).longValue();
+	}
+
+	/**
+	 * 转换为Integer类型
+	 */
+	public static Integer toInteger(Object val){
+		return toLong(val).intValue();
+	}
+
+	/**
+	 * 获得i18n字符串
+	 */
+	public static String getMessage(String code, Object[] args) {
+		LocaleResolver localLocaleResolver = (LocaleResolver) SpringContextHolder.getBean(LocaleResolver.class);
+		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+		Locale localLocale = localLocaleResolver.resolveLocale(request);
+		return SpringContextHolder.getApplicationContext().getMessage(code, args, localLocale);
+	}
+
+	/**
+	 * 获得用户远程地址
+	 */
+	public static String getRemoteAddr(HttpServletRequest request){
+		String remoteAddr = request.getHeader("X-Real-IP");
+		if (isNotBlank(remoteAddr)) {
+			remoteAddr = request.getHeader("X-Forwarded-For");
+		}else if (isNotBlank(remoteAddr)) {
+			remoteAddr = request.getHeader("Proxy-Client-IP");
+		}else if (isNotBlank(remoteAddr)) {
+			remoteAddr = request.getHeader("WL-Proxy-Client-IP");
+		}
+		return remoteAddr != null ? remoteAddr : request.getRemoteAddr();
+	}
+
+	/**
+	 * 驼峰命名法工具
+	 * @return
+	 * 		toCamelCase("hello_world") == "helloWorld"
+	 * 		toCapitalizeCamelCase("hello_world") == "HelloWorld"
+	 * 		toUnderScoreCase("helloWorld") = "hello_world"
+	 */
+	public static String toCamelCase(String s) {
+		if (s == null) {
+			return null;
+		}
+
+		s = s.toLowerCase();
+
+		StringBuilder sb = new StringBuilder(s.length());
+		boolean upperCase = false;
+		for (int i = 0; i < s.length(); i++) {
+			char c = s.charAt(i);
+
+			if (c == SEPARATOR) {
+				upperCase = true;
+			} else if (upperCase) {
+				sb.append(Character.toUpperCase(c));
+				upperCase = false;
+			} else {
+				sb.append(c);
+			}
+		}
+
+		return sb.toString();
+	}
+
+	/**
+	 * 驼峰命名法工具
+	 * @return
+	 * 		toCamelCase("hello_world") == "helloWorld"
+	 * 		toCapitalizeCamelCase("hello_world") == "HelloWorld"
+	 * 		toUnderScoreCase("helloWorld") = "hello_world"
+	 */
+	public static String toCapitalizeCamelCase(String s) {
+		if (s == null) {
+			return null;
+		}
+		s = toCamelCase(s);
+		return s.substring(0, 1).toUpperCase() + s.substring(1);
+	}
+
+	/**
+	 * 驼峰命名法工具
+	 * @return
+	 * 		toCamelCase("hello_world") == "helloWorld"
+	 * 		toCapitalizeCamelCase("hello_world") == "HelloWorld"
+	 * 		toUnderScoreCase("helloWorld") = "hello_world"
+	 */
+	public static String toUnderScoreCase(String s) {
+		if (s == null) {
+			return null;
+		}
+
+		StringBuilder sb = new StringBuilder();
+		boolean upperCase = false;
+		for (int i = 0; i < s.length(); i++) {
+			char c = s.charAt(i);
+
+			boolean nextUpperCase = true;
+
+			if (i < (s.length() - 1)) {
+				nextUpperCase = Character.isUpperCase(s.charAt(i + 1));
+			}
+
+			if ((i > 0) && Character.isUpperCase(c)) {
+				if (!upperCase || !nextUpperCase) {
+					sb.append(SEPARATOR);
+				}
+				upperCase = true;
+			} else {
+				upperCase = false;
+			}
+
+			sb.append(Character.toLowerCase(c));
+		}
+
+		return sb.toString();
+	}
+
+	/**
+	 * 如果不为空,则设置值
+	 * @param target
+	 * @param source
+	 */
+	public static void setValueIfNotBlank(String target, String source) {
+		if (isNotBlank(source)){
+			target = source;
+		}
+	}
+
+	/**
+	 * 转换为JS获取对象值,生成三目运算返回结果
+	 * @param objectString 对象串
+	 *   例如:row.user.id
+	 *   返回:!row?'':!row.user?'':!row.user.id?'':row.user.id
+	 */
+	public static String jsGetVal(String objectString){
+		StringBuilder result = new StringBuilder();
+		StringBuilder val = new StringBuilder();
+		String[] vals = split(objectString, ".");
+		for (int i=0; i<vals.length; i++){
+			val.append("." + vals[i]);
+			result.append("!"+(val.substring(1))+"?'':");
+		}
+		result.append(val.substring(1));
+		return result.toString();
+	}
+
+
+
+	/**
+	 * 获取字符首字母大小写
+	 */
+
+	public static String getPinYinHeadChar(String zn_str, int caseType) {
+		if(zn_str != null && !zn_str.trim().equalsIgnoreCase("")) {
+			char[] strChar = zn_str.toCharArray();
+			// 汉语拼音格式输出类
+			HanyuPinyinOutputFormat hanYuPinOutputFormat = new HanyuPinyinOutputFormat();
+			// 输出设置,大小写,音标方式等
+			if(1 == caseType) {
+				hanYuPinOutputFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
+			} else {
+				hanYuPinOutputFormat.setCaseType(HanyuPinyinCaseType.UPPERCASE);
+			}
+			hanYuPinOutputFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
+			hanYuPinOutputFormat.setVCharType(HanyuPinyinVCharType.WITH_V);
+			StringBuffer pyStringBuffer = new StringBuffer();
+			for(int i=0; i<strChar.length; i++) {
+				char c = strChar[i];
+				char pyc = strChar[i];
+				if(String.valueOf(c).matches("[\\u4E00-\\u9FA5]+")) {//是中文或者a-z或者A-Z转换拼音
+					try {
+						String[] pyStirngArray = PinyinHelper.toHanyuPinyinStringArray(strChar[i], hanYuPinOutputFormat);
+						if(null != pyStirngArray && pyStirngArray[0]!=null) {
+							pyc = pyStirngArray[0].charAt(0);
+							pyStringBuffer.append(pyc);
+						}
+					} catch(BadHanyuPinyinOutputFormatCombination e) {
+						e.printStackTrace();
+					}
+				}
+			}
+			return pyStringBuffer.toString();
+		}
+		return null;
+	}
+
+
+	public static boolean isChinese(char c) {
+		Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
+		if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
+				|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
+				|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
+				|| ub == Character.UnicodeBlock.GENERAL_PUNCTUATION) {
+			return true;
+		}
+		return false;
+	}
+
+	public static Map<String, String> StringToJson(String contentStr){
+		HashMap<String, String> requestMap = new HashMap<String, String>();
+
+
+		JSONObject jsonObject = JSONObject.fromObject(contentStr);//
+		Iterator<String> keys = jsonObject.keys();// 定义迭代器
+		String key = null;
+		String value = null;
+		while (keys.hasNext()) {
+			key = keys.next().toString();
+			value = jsonObject.get(key).toString();
+			requestMap.put(key.trim(), value.trim());
+		}
+		return requestMap;
+	}
+
+	/**
+	 * 根据键值对填充字符串,如("hello {name}",{name:"xiaoming"})
+	 * 输出:
+	 * @param content
+	 * @param map
+	 * @return
+	 */
+	public static String renderString(String content, Map<String, String> map){
+		Set<Map.Entry<String, String>> sets = map.entrySet();
+		for(Map.Entry<String, String> entry : sets) {
+			String regex = "\\{" + entry.getKey() + "\\}";
+			Pattern pattern = Pattern.compile(regex);
+			Matcher matcher = pattern.matcher(content);
+			content = matcher.replaceAll(entry.getValue());
+		}
+		return content;
+	}
+
+	/**
+	 * 提供精确的加法运算。
+	 * @param v1 被加数
+	 * @param v2 加数
+	 * @return 两个参数的和
+	 */
+	public static double add(double v1,double v2){
+		BigDecimal b1 = new BigDecimal(Double.toString(v1));
+		BigDecimal b2 = new BigDecimal(Double.toString(v2));
+		return b1.add(b2).doubleValue();
+	}
+	/**
+	 * 提供精确的减法运算。
+	 * @param v1 被减数
+	 * @param v2 减数
+	 * @return 两个参数的差
+	 */
+	public static double sub(double v1,double v2){
+		BigDecimal b1 = new BigDecimal(Double.toString(v1));
+		BigDecimal b2 = new BigDecimal(Double.toString(v2));
+		return b1.subtract(b2).doubleValue();
+	}
+	/**
+	 * 提供精确的乘法运算。
+	 * @param v1 被乘数
+	 * @param v2 乘数
+	 * @return 两个参数的积
+	 */
+	public static double mul(double v1,double v2){
+		BigDecimal b1 = new BigDecimal(Double.toString(v1));
+		BigDecimal b2 = new BigDecimal(Double.toString(v2));
+		return b1.multiply(b2).doubleValue();
+	}
+	/**
+	 * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
+	 * 小数点以后10位,以后的数字四舍五入。
+	 * @param v1 被除数
+	 * @param v2 除数
+	 * @return 两个参数的商
+	 */
+	public static double div(double v1,double v2){
+		return div(v1,v2,DEF_DIV_SCALE);
+	}
+	/**
+	 * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
+	 * 定精度,以后的数字四舍五入。
+	 * @param v1 被除数
+	 * @param v2 除数
+	 * @param scale 表示表示需要精确到小数点以后几位。
+	 * @return 两个参数的商
+	 */
+	public static double div(double v1,double v2,int scale){
+		if(scale<0){
+			throw new IllegalArgumentException(
+					"The scale must be a positive integer or zero");
+		}
+		BigDecimal b1 = new BigDecimal(Double.toString(v1));
+		BigDecimal b2 = new BigDecimal(Double.toString(v2));
+		return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
+	}
+	/**
+	 * 提供精确的小数位四舍五入处理。
+	 * @param v 需要四舍五入的数字
+	 * @param scale 小数点后保留几位
+	 * @return 四舍五入后的结果
+	 */
+	public static double round(double v,int scale){
+		if(scale<0){
+			throw new IllegalArgumentException("The scale must be a positive integer or zero");
+		}
+		BigDecimal b = new BigDecimal(Double.toString(v));
+		BigDecimal one = new BigDecimal("1");
+		return b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
+	}
+
+	public static Map<String,String> getByDictMap(){
+		Map<String,String> map = new HashMap<>();
+		map.put("13","报销申请");
+		map.put("16","合同申请");
+		map.put("21","发票申请");
+		map.put("38","案例登记");
+		map.put("39","项目登记");
+		map.put("40","退票申请");
+		map.put("41","项目变更");
+		map.put("42","合同归档");
+		map.put("43","合同作废");
+		map.put("44","合同变更");
+		map.put("45","报告申请");
+		map.put("46","报告变更");
+		map.put("47","报告作废");
+		map.put("48","发票变更");
+		map.put("49","退票变更");
+		map.put("50","投标申请");
+		map.put("51","报告归档");
+		map.put("52","收入结算");
+		map.put("53","收入调整");
+		map.put("54","调整作废");
+		map.put("55","收文申请");
+		map.put("56","行政盖章");
+		map.put("57","采购合同");
+		map.put("58","日常事务");
+		map.put("59","借用申请");
+		map.put("60","归还借用");
+		map.put("61","采购申请");
+		map.put("62","发文申请");
+		map.put("63","报废申请");
+		map.put("64","领用申请");
+		map.put("66","转正申请");
+		map.put("67","劳动关系");
+		map.put("68","部门调转");
+		map.put("69","日常事务");
+		map.put("70","职级调整");
+		map.put("71","离职申请");
+		map.put("72","合同完成");
+		map.put("74","系统预警");
+		map.put("75","加入企业");
+		map.put("76","案例申请");
+		map.put("77","加班申请");
+		map.put("78","出差申请");
+		map.put("79","外勤申请");
+		map.put("80","请假申请");
+		map.put("81","销假申请");
+		map.put("82","续假申请");
+		map.put("83","补卡申请");
+		map.put("84","考勤审批");
+		return map;
+	}
+
+	public static String firstDay(String month,String day,String companyId) {
+		if(StringUtils.isBlank(month)) {
+			if (StringUtils.isBlank(day)) {
+				//获取上月第一天:
+				Calendar c = Calendar.getInstance();
+				c.add(Calendar.MONTH, -1);
+				c.set(Calendar.DAY_OF_MONTH, 1);//设置为1号,当前日期既为本月第一天
+				String first = format.format(c.getTime());
+				return first;
+			}else{
+				Calendar now = Calendar.getInstance();
+				int nowDay = now.get(Calendar.DAY_OF_MONTH);
+				now.set(Calendar.DAY_OF_MONTH, 0);
+				String last = format.format(now.getTime()).substring(8,10);
+				if (last.equals(day)){
+					return format.format(now.getTime()).substring(0,8)+"01";
+				}else {
+					if (nowDay < Integer.parseInt(day)) {
+						//获取上月第一天:
+						Calendar c = Calendar.getInstance();
+						c.add(Calendar.MONTH, -2);
+						c.set(Calendar.DAY_OF_MONTH, 1);//设置为1号,当前日期既为本月第一天
+						String first = format.format(c.getTime()).substring(0, 8) + (Integer.parseInt(day) < 10 ? "0" + Integer.parseInt(day) : day);
+						return first;
+					} else {
+						//获取上月第一天:
+						Calendar c = Calendar.getInstance();
+						c.add(Calendar.MONTH, -1);
+						c.set(Calendar.DAY_OF_MONTH, 1);//设置为1号,当前日期既为本月第一天
+						String first = format.format(c.getTime()).substring(0, 8) + (Integer.parseInt(day) < 10 ? "0" + Integer.parseInt(day) : day);
+						return first;
+					}
+				}
+			}
+		}else{
+			if (StringUtils.isBlank(day)) {
+				return month+"-01";
+			}else {
+				int m = Integer.parseInt(month.substring(5,7))-1;
+				if (m==1){
+					int year = Integer.parseInt(month.substring(0,4)) - 1;
+					return year+"-01-"+(Integer.parseInt(day)<10?"0"+day:day);
+				}else if(m>10){
+					return month.substring(0,5)+m+"-"+(Integer.parseInt(day)<10?"0"+Integer.parseInt(day):day);
+				}else{
+					return month.substring(0,5)+"0"+m+"-"+(Integer.parseInt(day)<10?"0"+Integer.parseInt(day):day);
+				}
+			}
+		}
+	}
+	public static String lastDay(String month,String day,String companyId) {
+		if(StringUtils.isBlank(month)) {
+			if (StringUtils.isBlank(day)) {
+				//获取上月最后一天
+				Calendar ca = Calendar.getInstance();
+				ca.set(Calendar.DAY_OF_MONTH, 0);
+				String last = format.format(ca.getTime());
+				return last;
+			}else{
+				Calendar now = Calendar.getInstance();
+				int nowDay = now.get(Calendar.DAY_OF_MONTH);
+				now.set(Calendar.DAY_OF_MONTH, 0);
+				String l = format.format(now.getTime()).substring(8,10);
+				if (l.equals(day)){
+					return format.format(now.getTime()).substring(0,8)+day;
+				}else {
+					if (nowDay < Integer.parseInt(day)) {
+						//获取上月最后一天
+
+						int days = Integer.parseInt(day) - 1;
+						if (days>0) {
+							Calendar ca = Calendar.getInstance();
+							ca.set(Calendar.DAY_OF_MONTH, 0);
+							String last = format.format(ca.getTime()).substring(0, 8) + (days < 10 ? "0" + days : days);
+							return last;
+						}else {
+							Calendar ca = Calendar.getInstance();
+							ca.set(Calendar.DAY_OF_MONTH, 1);
+							return format.format(ca.getTime());
+						}
+					} else {
+						//获取上月最后一天
+						int days = Integer.parseInt(day) - 1;
+						if (days>0) {
+							Calendar ca = Calendar.getInstance();
+							ca.set(Calendar.DAY_OF_MONTH, +1);
+							String last = format.format(ca.getTime()).substring(0, 8) + (days < 10 ? "0" + days : days);
+							return last;
+						}else {
+							Calendar ca = Calendar.getInstance();
+							ca.set(Calendar.DAY_OF_MONTH, 0);
+							return format.format(ca.getTime());
+						}
+					}
+				}
+			}
+		}else {
+			if (StringUtils.isBlank(day)) {
+				//格式化日期
+				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+				Calendar cal = Calendar.getInstance();
+				//设置年份
+				cal.set( Integer.parseInt(month.substring(0,4)),(Integer.parseInt(month.substring(5,7))-1),1);
+				//设置月份
+				//获取某月最大天数
+				int lastDay = cal.getActualMaximum(Calendar.DATE);
+				//设置日历中月份的最大天数
+				cal.set(Calendar.DAY_OF_MONTH, lastDay);
+				return sdf.format(cal.getTime());
+			}else {
+				int days = Integer.parseInt(day)-1;
+				if (days>0){
+					return month+"-"+(days<10?"0"+days:days);
+				}else{
+					Calendar calendar = Calendar.getInstance();
+					Date date = null;
+					try {
+						date = format.parse(month+"-01");
+					} catch (ParseException e) {
+						e.printStackTrace();
+					}
+					calendar.setTime(date);
+					calendar.set(Calendar.DAY_OF_MONTH, -1);
+					int lastDay = calendar.getActualMaximum(Calendar.DATE);
+					//设置日历中月份的最大天数
+					calendar.set(Calendar.DAY_OF_MONTH, lastDay);
+					return format.format(calendar.getTime());
+				}
+			}
+		}
+	}
+	public static Boolean isWeek(String day) {
+		SimpleDateFormat sdfDay = new SimpleDateFormat("yyyy-MM-dd");
+		Date date= null;//取时间
+		try {
+			date = sdfDay.parse(day);
+			Calendar calendar = Calendar.getInstance();
+			calendar.setTime(date);
+			int week  =  calendar.get(Calendar.DAY_OF_WEEK)-1;
+			if (week==0 || week==6){
+				return true;
+			}else {
+				return false;
+			}
+		} catch (ParseException e) {
+			e.printStackTrace();
+		}
+		return false;
+	}
+
+	public static int lateEarlyTime(String cardType,Date start,Date end,Date now){
+		Integer nowh = Integer.parseInt(sdfs.format(new Date()).substring(0,2));
+		Integer nowm = Integer.parseInt(sdfs.format(new Date()).substring(2,4));
+		if (cardType.equals("1")){
+			Integer ruleh = Integer.parseInt(sdfs.format(start).substring(0,2));
+			Integer rulem = Integer.parseInt(sdfs.format(start).substring(2,4));
+			if (ruleh - nowh < 0 && rulem >= nowm){
+				return nowh - ruleh;
+			}else if(ruleh - nowh < 0 && rulem < nowm){
+				return nowh - ruleh + 1;
+			}else {
+				return 0;
+			}
+		}else {
+			Integer ruleh = Integer.parseInt(sdfs.format(end).substring(0,2));
+			Integer rulem = Integer.parseInt(sdfs.format(end).substring(2,4));
+			if (ruleh - nowh > 0 && rulem > nowm){
+				return ruleh - nowh + 1;
+			}else if(ruleh - nowh > 0 && rulem <= nowm){
+				return ruleh - nowh;
+			}else {
+				return 0;
+			}
+		}
+	}
+
+	public static Map<String,String> getMonth() {
+		//获取上月最后一天
+		Calendar ca = Calendar.getInstance();
+		String month = format.format(ca.getTime()).substring(0,7);
+		ca.set(Calendar.DAY_OF_MONTH, 0);
+		String oldMonth = format.format(ca.getTime()).substring(0,7);
+		Map<String,String> map = new HashMap<>();
+		map.put("1",month);
+		map.put("2",oldMonth);
+		return map;
+	}
+
+
+	/**
+	 * date转Str
+	 * @param currentTime
+	 * @return
+	 */
+	public static String getDateStr(Date currentTime) {
+		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
+		String dateString = formatter.format(currentTime);
+		return dateString;
+	}
+}

+ 30 - 15
pom.xml

@@ -226,21 +226,36 @@
             <version>4.3.0</version>
         </dependency>
 
-        <!--<dependency>-->
-            <!--<groupId>org.apache.poi</groupId>-->
-            <!--<artifactId>poi</artifactId>-->
-            <!--<version>3.17</version>-->
-        <!--</dependency>-->
-        <!--<dependency>-->
-            <!--<groupId>org.apache.poi</groupId>-->
-            <!--<artifactId>poi-ooxml</artifactId>-->
-            <!--<version>3.17</version>-->
-        <!--</dependency>-->
-        <!--<dependency>-->
-            <!--<groupId>org.apache.poi</groupId>-->
-            <!--<artifactId>poi-ooxml-schemas</artifactId>-->
-            <!--<version>3.17</version>-->
-        <!--</dependency>-->
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi</artifactId>
+            <version>3.17</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+            <version>3.17</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml-schemas</artifactId>
+            <version>3.17</version>
+        </dependency>
+        <dependency>
+            <groupId>com.belerweb</groupId>
+            <artifactId>pinyin4j</artifactId>
+            <version>2.5.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.belerweb</groupId>
+            <artifactId>pinyin4j</artifactId>
+            <version>2.5.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-core</artifactId>
+            <version>1.2.3</version>
+        </dependency>