浏览代码

Merge branch 'release' of lvjian/wxbase into release

吕健 2 年之前
父节点
当前提交
f6635ba035

+ 6 - 0
sql/2023-6-6/福庆Eid配置.sql

@@ -0,0 +1,6 @@
+INSERT INTO `wx_base`.`eid_merch` (`merch_sn`, `secret_id`, `secret_key`, `merch_id`, `token_expired`, `tstm`) VALUES ('mhbs174902211850035200', 'AKIDUox1swlLfjbFeleNtAdrpXyEEySlqgGc', 'ED1c0AAwVrzue9Tav4ye8NO9f095mHXX', '0NSJ2305041629298230', 4800, '2023-05-06 10:14:18');
+
+INSERT INTO `wx_base`.`merch_app` (`merch_sn`, `app_code`, `app_name`, `tstm`) VALUES ('mhbs174902211850035200', 'kmall-emato', 'Kmall福庆', '2023-05-06 10:10:39');
+
+
+INSERT INTO `wx_base`.`merch_info` (`merch_sn`, `merch_name`, `tstm`) VALUES ('mhbs174902211850035200', '福庆新零售', '2023-05-06 10:09:14');

+ 5 - 0
src/main/java/com/ematou/wxbase/common/constant/RedisKey.java

@@ -13,4 +13,9 @@ public class RedisKey {
      * 获取E证通 token 缓存键前缀
      */
     public static final String GET_EID_TOKEN = "get_eid_token:";
+
+    /**
+     * 获取 wx_ticket 缓存键
+     */
+    public static final String GET_WX_TICKET = "get_wx_ticket";
 }

+ 1 - 0
src/main/java/com/ematou/wxbase/common/constant/TokenType.java

@@ -18,6 +18,7 @@ public enum TokenType {
 
     WX_TOKEN("0", "微信 token"),
     EID_TOKEN("1", "E证通 token"),
+    WX_TICKET("2", "微信 ticket"),
     ;
 
 

+ 11 - 12
src/main/java/com/ematou/wxbase/config/WxGeneralConfig.java

@@ -1,18 +1,6 @@
 package com.ematou.wxbase.config;
 
-import com.ematou.wxbase.common.utils.DateUtils;
-import com.ematou.wxbase.entity.OperationRecord;
-import com.ematou.wxbase.entity.TokenRecord;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-import org.springframework.web.client.RestTemplate;
-
-import java.util.Date;
 
 /**
  * @author lhm
@@ -33,6 +21,9 @@ public class WxGeneralConfig {
     @Value("${wx.general.url}")
     private String url;
 
+    @Value("${wx.general.ticketUrl}")
+    private String ticketUrl;
+
     public String getAppId() {
         return appId;
     }
@@ -64,4 +55,12 @@ public class WxGeneralConfig {
     public void setUrl(String url) {
         this.url = url;
     }
+
+    public String getTicketUrl() {
+        return ticketUrl;
+    }
+
+    public void setTicketUrl(String ticketUrl) {
+        this.ticketUrl = ticketUrl;
+    }
 }

+ 52 - 0
src/main/java/com/ematou/wxbase/controller/TicketController.java

@@ -0,0 +1,52 @@
+package com.ematou.wxbase.controller;
+
+import com.ematou.wxbase.common.web.R;
+import com.ematou.wxbase.service.TicketRecordService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 获取微信 ticket 控制器
+ *
+ * @author frankeleyn
+ * @email lvjian@qhdswl.com
+ * @date 2023/5/11 15:49
+ */
+@RestController
+public class TicketController {
+
+    @Autowired
+    private TicketRecordService ticketRecordService;
+
+    /**
+     * 获取微信票据
+     *
+     * @param url
+     * @return
+     */
+    @GetMapping("/wxbase/getTicket")
+    public R<?> getTicket(String url) {
+        try {
+            return new R<>().success(ticketRecordService.getTicket(url));
+        } catch (Exception e) {
+            return new R<>().error("获取wxTicket失败!errorMessage: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 生成微信票据
+     *
+     * @param url
+     * @return
+     */
+    @GetMapping("/wxbase/genTicket")
+    public R<?> genTicket(String url) {
+        try {
+            return new R<>().success(ticketRecordService.genTicket(url));
+        } catch (Exception e) {
+            return new R<>().error("获取wxTicket失败!errorMessage: " + e.getMessage());
+        }
+    }
+
+}

+ 33 - 0
src/main/java/com/ematou/wxbase/entity/TicketRecord.java

@@ -0,0 +1,33 @@
+package com.ematou.wxbase.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 微信票据记录实体类
+ *
+ * @author frankeleyn
+ * @email lvjian@qhdswl.com
+ * @date 2023/5/11 17:04
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class TicketRecord {
+
+    private Integer id;
+    private String appId;// appid
+    private String ticket;// 微信票据
+    private String generationTime;// 生成时间
+    private String expireTime;// 过期时间
+    private Integer expiresIn;// 有效时间(单位:秒)
+    private String timeStamp;// 时间戳
+    private String nonceStr;// 随机字符串(用于签名)
+    private String sign;// 签名
+    private String reqUrl;// 请求的 Url
+
+
+}

+ 25 - 0
src/main/java/com/ematou/wxbase/mapper/TicketRecordMapper.java

@@ -0,0 +1,25 @@
+package com.ematou.wxbase.mapper;
+
+import com.ematou.wxbase.entity.TicketRecord;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 微信票据 Mapper
+ *
+ * @author frankeleyn
+ * @email lvjian@qhdswl.com
+ * @date 2023/5/11 19:56
+ */
+@Mapper
+public interface TicketRecordMapper {
+
+    /**
+     * 插入微信票据
+     *
+     * @param record
+     * @return
+     */
+    int insertRecord(TicketRecord record);
+
+
+}

+ 28 - 0
src/main/java/com/ematou/wxbase/service/TicketRecordService.java

@@ -0,0 +1,28 @@
+package com.ematou.wxbase.service;
+
+import com.ematou.wxbase.entity.TicketRecord;
+
+/**
+ * 微信 ticket 业务类
+ *
+ * @author frankeleyn
+ * @email lvjian@qhdswl.com
+ * @date 2023/5/11 15:57
+ */
+public interface TicketRecordService {
+
+    /**
+     * 获取微信票据
+     * @param url 请求 wxJSsdk 的网页 url
+     * @return
+     */
+    TicketRecord getTicket(String url);
+
+    /**
+     * 生成微信票据
+     *
+     * @param url 请求 wxJSsdk 的网页 url
+     */
+    TicketRecord genTicket(String url);
+
+}

+ 285 - 0
src/main/java/com/ematou/wxbase/service/impl/TicketRecordServiceImpl.java

@@ -0,0 +1,285 @@
+package com.ematou.wxbase.service.impl;
+
+import com.ematou.wxbase.common.constant.RedisKey;
+import com.ematou.wxbase.common.constant.TokenType;
+import com.ematou.wxbase.config.WxGeneralConfig;
+import com.ematou.wxbase.entity.OperationRecord;
+import com.ematou.wxbase.entity.TicketRecord;
+import com.ematou.wxbase.entity.TokenRecord;
+import com.ematou.wxbase.exception.Assert;
+import com.ematou.wxbase.exception.ServiceException;
+import com.ematou.wxbase.mapper.OperationRecordMapper;
+import com.ematou.wxbase.mapper.TicketRecordMapper;
+import com.ematou.wxbase.service.TicketRecordService;
+import com.ematou.wxbase.service.TokenRecordService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+import org.springframework.web.client.RestTemplate;
+
+import javax.annotation.Resource;
+import java.security.MessageDigest;
+import java.text.ParseException;
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+
+/**
+ * 微信票据接口实现类
+ *
+ * @author frankeleyn
+ * @email lvjian@qhdswl.com
+ * @date 2023/5/11 16:04
+ */
+@Service
+public class TicketRecordServiceImpl implements TicketRecordService {
+
+    private static final Logger logger = LoggerFactory.getLogger(TicketRecordServiceImpl.class);
+
+    @Autowired
+    private RestTemplate restTemplate;
+
+    @Autowired
+    private WxGeneralConfig wxGeneralConfig;
+
+    @Autowired
+    private TokenRecordService tokenRecordService;
+
+    @Resource
+    private OperationRecordMapper operationRecordMapper;
+
+    @Resource
+    private TicketRecordMapper ticketRecordMapper;
+
+    @Autowired
+    private RedisTemplate<String, Object> redisTemplate;
+
+
+    /**
+     * 获取微信票据
+     *
+     * @param url
+     * @return
+     */
+    @Override
+    public TicketRecord getTicket(String url) {
+        // 获取缓存中的 wxTicket
+        TicketRecord ticketRecord =
+                (TicketRecord) redisTemplate.opsForValue().get(RedisKey.GET_WX_TICKET);
+
+        if (Objects.nonNull(ticketRecord)) {
+            // 如果缓存有数据直接返回
+            return ticketRecord;
+        }else {
+            // 如果没有缓存就生成一个
+            TicketRecord record = genTicket(url);
+            // 将E证通 token 设置进 Redis,并设置过期时间
+            redisTemplate.opsForValue().set(RedisKey.GET_WX_TICKET, record, Duration.ofSeconds(7200L));
+            return record;
+        }
+    }
+
+
+    /**
+     * 生成微信票据
+     *
+     * @param url
+     */
+    @Override
+    public TicketRecord genTicket(String url) {
+
+        Map<String, String> result = new HashMap<>();
+        // 获取微信 token
+        TokenRecord latestToken = null;
+        try {
+            latestToken = tokenRecordService.getLatestToken();
+        } catch (ParseException e) {
+            logger.error("获取微信 token 失败", e);
+            throw new RuntimeException("获取微信 token 失败!");
+        }
+
+        String accessToken = latestToken.getAccessToken();
+        logger.info("微信返回的 accessToken => {}", accessToken);
+
+        // 请求微信 url
+        String reqWxUrl = String.format(wxGeneralConfig.getTicketUrl(), accessToken);
+        logger.info("请求微信票据 url => {}", reqWxUrl);
+
+        Map wxRes = null;
+        try {
+            wxRes = restTemplate.getForObject(reqWxUrl, Map.class);
+            logger.info("请求微信票据返回信息 => {}", wxRes );
+        } catch (Exception e) {
+            logger.error("请求微信票据失败 ", e);
+            throw new ServiceException("请求微信票据失败!");
+        }
+
+        logger.info("微信返回信息 => {}", wxRes);
+
+        if (null == wxRes) {
+            logger.error("请求微信票据失败!errorMessage:response is null");
+            throw new ServiceException("请求微信票据失败,微信响应为空!");
+        }
+
+        // 获取返回的 ticket 和过期时间
+        String ticket = (String) wxRes.get("ticket");
+        Integer expiresIn = (Integer) wxRes.get("expires_in");
+
+        if(!StringUtils.hasLength(ticket) && expiresIn == null){
+            // 如果票据和过期时间不存在
+            Object errcode = wxRes.get("errcode");
+            Object errmsg = wxRes.get("errmsg");
+            logger.error("请求微信票据失败! => {}", wxRes);
+            throw new ServiceException("请求微信票据失败! errorCode: " + errcode + ",errorMessage:" + errmsg);
+        }
+
+        // 生成随机字符串
+        String nonceStr = createNonceStr();
+        // 生成时间戳
+        String timestamp = createTimeStamp();
+        // 组装签名串
+        String signParam = getSignParam(url, ticket, nonceStr, timestamp);
+        // 签名
+        String signature = getSign(signParam);
+        logger.info("签名 => {}", signature);
+        // 插入操作记录
+        insertOprationRecord();
+        // 插入微信 ticket
+        TicketRecord ticketRecord = insertTicketRecord(url, ticket, expiresIn, nonceStr, timestamp, signature);
+        result.put("appId", wxGeneralConfig.getAppId());
+        result.put("ticket", ticket);
+        result.put("timestamp", timestamp);
+        result.put("nonceStr", nonceStr);
+        result.put("signature", signature);
+
+        // 获取微信票据
+        return ticketRecord;
+    }
+
+    /**
+     * 插入 wx ticket
+     * @param url
+     * @param ticket
+     * @param expiresIn
+     * @param nonceStr
+     * @param timestamp
+     * @param signature
+     * @return
+     */
+    private TicketRecord insertTicketRecord(String url, String ticket, Integer expiresIn, String nonceStr, String timestamp, String signature) {
+        // 生成时间
+        LocalDateTime generationTime = LocalDateTime.now();
+        // 过期时间
+        LocalDateTime expireTime = generationTime.plusSeconds(expiresIn.longValue());
+        // 对时间进行格式化
+        String generationTimeStr = generationTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+        String expireTimeStr = expireTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+
+        // 插入ticket 记录
+        TicketRecord ticketRecord =
+                TicketRecord.builder()
+                        .appId(wxGeneralConfig.getAppId())
+                        .ticket(ticket)
+                        .generationTime(generationTimeStr)
+                        .expireTime(expireTimeStr)
+                        .expiresIn(expiresIn)
+                        .timeStamp(timestamp)
+                        .nonceStr(nonceStr)
+                        .sign(signature)
+                        .reqUrl(url)
+                        .build();
+        int insert = ticketRecordMapper.insertRecord(ticketRecord);
+        Assert.notTrue(insert < 1, "插入微信 ticket 记录失败!");
+        return ticketRecord;
+    }
+
+    /**
+     * 插入操作记录
+     */
+    private void insertOprationRecord() {
+        // 插入操作记录
+        OperationRecord operationRecord =
+                OperationRecord.builder()
+                        .appCode("暂无")
+                        .tokenType(TokenType.WX_TICKET.getItem())
+                        .build();
+        operationRecordMapper.insertRecord(operationRecord);
+    }
+
+
+    /**
+     * 组装加签字符串
+     *
+     * @param url
+     * @param ticket
+     * @param nonceStr
+     * @param timestamp
+     * @return
+     */
+    private String getSignParam(String url, String ticket, String nonceStr, String timestamp) {
+        // 加签字符串
+        String string1;
+        //注意这里参数名必须全部小写,且必须有序
+        string1 = "jsapi_ticket=" + ticket +
+                "&noncestr=" + nonceStr +
+                "&timestamp=" + timestamp +
+                "&url=" + url;
+        logger.info("加签字符串 => {}", string1);
+        return string1;
+    }
+
+    /**
+     * 签名
+     *
+     * @param string1 加签字符串
+     * @return
+     */
+    private String getSign(String string1) {
+        try {
+            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
+            crypt.reset();
+            crypt.update(string1.getBytes("UTF-8"));
+            return byteToHex(crypt.digest());
+        } catch (Exception e) {
+            logger.error("签名失败!", e);
+            throw new RuntimeException("请求微信票据签名失败!");
+        }
+    }
+
+    /**
+     * 产生随机串--由程序自己随机产生
+     * @return
+     */
+    private static String createNonceStr() {
+        return UUID.randomUUID().toString().replace("-", "");
+    }
+
+    /**
+     * 由程序自己获取当前时间
+     * @return
+     */
+    private static String createTimeStamp() {
+        return Long.toString(System.currentTimeMillis() / 1000);
+    }
+
+    /**
+     * 随机加密
+     * @param hash
+     * @return
+     */
+    private static String byteToHex(final byte[] hash) {
+        Formatter formatter = new Formatter();
+        for (byte b : hash)
+        {
+            formatter.format("%02x", b);
+        }
+        String result = formatter.toString();
+        formatter.close();
+        return result;
+    }
+
+}

+ 6 - 3
src/main/resources/application-test.yml

@@ -5,9 +5,12 @@ spring:
   # 数据源配置
   datasource:
     driver-class-name: com.mysql.cj.jdbc.Driver
-    username: tuser
-    password: Qq!123
-    url: jdbc:mysql://47.112.115.196:3306/wx_base?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
+#    username: tuser
+#    password: Qq!123
+#    url: jdbc:mysql://47.112.115.196:3306/wx_base?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
+    username: wx_base
+    password: goZ7ooGmxV
+    url: jdbc:mysql://out-rm-wz92efl25x02n44xego.mysql.rds.aliyuncs.com:3306/wx_base?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
   # redis 配置
   redis:
     database: 1

+ 1 - 0
src/main/resources/application.yml

@@ -4,6 +4,7 @@ wx:
     appSecret: 78413a82d0332ecbf7fdf475d0a8b08e
     grantType: client_credential
     url: https://api.weixin.qq.com/cgi-bin/token?grant_type=%s&appid=%s&secret=%s
+    ticketUrl: https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi
 
 spring:
   # 环境切换

+ 168 - 42
src/main/resources/logback.xml

@@ -1,54 +1,180 @@
-<configuration>
-    <!-- %m输出的信息, %p日志级别, %t线程名, %d日期, %c类的全名, %i索引 -->
-    <!-- appender是configuration的子节点,是负责写日志的组件 -->
-    <!-- ConsoleAppender把日志输出到控制台 -->
-    <!--    <property name="CONSOLE_LOG_PATTERN" -->
-    <!--               value="%date{yyyy-MM-dd HH:mm:ss} | %highlight(%-5level) | %boldYellow(%thread) | %boldGreen(%logger) | %msg%n"/> -->
-    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+<?xml version="1.0" encoding="UTF-8"?>
+
+<configuration scan="false" scanPeriod="60 seconds" debug="false">
+
+    <property name="LOG_HOME" value="logs/"/>
+    <!-- 定义日志的根目录 -->
+    <property name="TRACE_DIR" value="trace" />
+    <property name="DEBUG_DIR" value="debug" />
+    <property name="INFO_DIR" value="info" />
+    <property name="WARN_DIR" value="warn" />
+    <property name="ERROR_DIR" value="error" />
+    <!-- 定义日志文件名称 -->
+    <property name="TRACE_FILE_NAME" value="wxbase-trace"></property>
+    <property name="DEBUG_FILE_NAME" value="wxbase-debug"></property>
+    <property name="INFO_FILE_NAME" value="wxbase-info"></property>
+    <property name="WARN_FILE_NAME" value="wxbase-warn"></property>
+    <property name="ERROR_FILE_NAME" value="wxbase-error"></property>
+
+    <!-- 定义日志级别颜色 -->
+    <!-- 控制台显示 -->
+    <property name="STD_CONSOLE_LOG_PATTERN"
+              value="%d{yyyy-MM-dd HH:mm:ss.SSS}[%yellow(%thread)]-[%highlight(%-5level)][%green(%logger{70}):%cyan(%line)] - %msg%n"/>
+
+    <!-- 日志文件打印 -->
+    <property name="CONSOLE_LOG_PATTERN"
+              value="%d{yyyy-MM-dd HH:mm:ss.SSS}[%thread]-[%-5level][%logger{70}:%line] - %msg%n"/>
+
+    <!-- ConsoleAppender 控制台输出 appender -->
+    <appender name="stdoutAppender" class="ch.qos.logback.core.ConsoleAppender">
+        <!--
+        日志输出格式:%d表示日期时间,%thread表示线程名,%-5level:级别从左显示5个字符宽度
+        %logger{70} 表示logger名字最长50个字符,否则按照句点分割。 %msg:日志消息,%n是换行符
+        -->
+        <encoder>
+            <pattern>${STD_CONSOLE_LOG_PATTERN}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+
+
+    <!-- TRACE 日志 appender  -->
+    <appender name="traceAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 指定日志文件的名称 -->
+        <file>${LOG_HOME}/${TRACE_DIR}/${TRACE_FILE_NAME}.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_HOME}/${TRACE_DIR}/${TRACE_FILE_NAME}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
+            <MaxHistory>365</MaxHistory>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>10MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>TRACE</level>
+            <!--<onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>-->
+        </filter>
+    </appender>
+
+
+    <!-- DEBUG 日志 appender  -->
+    <appender name="debugAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 指定日志文件的名称 -->
+        <file>${LOG_HOME}/${DEBUG_DIR}/${DEBUG_FILE_NAME}.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_HOME}/${DEBUG_DIR}/${DEBUG_FILE_NAME}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
+            <MaxHistory>365</MaxHistory>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>10MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+        </rollingPolicy>
         <encoder>
-            <!--<pattern>${CONSOLE_LOG_PATTERN}</pattern> -->
-            <pattern>%date{yyyy-MM-dd HH:mm:ss} %highlight(%-5level) (%file:%line\)- %m%n</pattern>
-            <!-- 控制台也要使用utf-8,不要使用gbk -->
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
             <charset>UTF-8</charset>
         </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>DEBUG</level>
+            <!--<onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>-->
+        </filter>
     </appender>
 
-    <!-- RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
-    <!-- 1.先按日期存日志,日期变了,将前一天的日志文件名重命名为xxx%日期%索引,新的日志仍然是sys.log -->
-    <!-- 2.如果日期没有变化,但是当前日志文件的大小超过1kb时,对当前日志进行分割 重名名 -->
-    <appender name="syslog" class="ch.qos.logback.core.rolling.RollingFileAppender">
-        <!--<File>${catalina.base}/mylog/sys.log</File>-->
-        <File>/app/project/wx_base/logs/wxbase.log</File>
-        <!-- rollingPolicy:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。 -->
-        <!-- TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动 -->
+
+    <!-- phrase 日志 appender  -->
+    <appender name="infoAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 指定日志文件的名称 -->
+        <file>${LOG_HOME}/${INFO_DIR}/${INFO_FILE_NAME}.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_HOME}/${INFO_DIR}/${INFO_FILE_NAME}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
+            <MaxHistory>365</MaxHistory>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>10MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>INFO</level>
+            <!--<onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>-->
+        </filter>
+    </appender>
+
+
+    <!-- WARN 日志 appender  -->
+    <appender name="warnAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 指定日志文件的名称 -->
+        <file>${LOG_HOME}/${WARN_DIR}/${WARN_FILE_NAME}.log</file>
         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
-            <!-- 活动文件的名字会根据fileNamePattern的值,每隔一段时间改变一次 -->
-            <!--<fileNamePattern>${catalina.base}/mylog/sys.%d.%i.log</fileNamePattern>-->
-            <fileNamePattern>${catalina.base}/%d/sys.%d.%i.log</fileNamePattern>
-            <!-- 每产生一个日志文件,该日志文件的保存期限为30天 -->
-            <maxHistory>30</maxHistory>
-            <timeBasedFileNamingAndTriggeringPolicy  class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
-                <!-- maxFileSize:这是活动文件的大小,默认值是10MB,本篇设置为1KB,只是为了演示 -->
-                <maxFileSize>1KB</maxFileSize>
+            <fileNamePattern>${LOG_HOME}/${WARN_DIR}/${WARN_FILE_NAME}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
+            <MaxHistory>365</MaxHistory>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>10MB</maxFileSize>
             </timeBasedFileNamingAndTriggeringPolicy>
         </rollingPolicy>
         <encoder>
-            <!-- pattern节点,用来设置日志的输入格式 -->
-            <pattern>
-                %d %p (%file:%line\)- %m%n
-            </pattern>
-            <!-- 记录日志的编码 -->
-            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+            <charset>UTF-8</charset>
         </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>WARN</level>
+            <!--<onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>-->
+        </filter>
     </appender>
-    <!-- 控制台日志输出级别 -->
-    <root level="info">
-        <appender-ref ref="STDOUT" />
+
+
+    <!-- ERROR 日志 appender  -->
+    <appender name="errorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 指定日志文件的名称 -->
+        <file>${LOG_HOME}/${ERROR_DIR}/${ERROR_FILE_NAME}.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_HOME}/${ERROR_DIR}/${ERROR_FILE_NAME}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
+            <MaxHistory>365</MaxHistory>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>10MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印错误日志 -->
+            <level>ERROR</level>
+        </filter>
+    </appender>
+
+    <logger name="org.apache.shiro" level="DEBUG" additivity="false" />
+    <logger name="com.zaxxer.hikari" level="ERROR" additivity="false" />
+    <logger name="org.apache" level="ERROR" />
+    <logger name="org.springframework.context.annotation.ClassPathBeanDefinitionScanner" level="INFO" />
+    <logger name="org.springframework.beans.factory.support.DefaultListableBeanFactory" level="INFO" />
+    <logger name="org.springframework.data.convert.CustomConversions" level="INFO"/>
+    <logger name="org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener" level="INFO" />
+    <logger name="org.springframework.boot.autoconfigure.web.servlet.WelcomePageHandlerMapping" level="INFO" />
+    <logger name="org.springframework" level="DEBUG" />
+    <logger name="io.netty" level="INFO" />
+    <logger name="org.mybatis" level="INFO" />
+    <logger name="org.hibernate" level="INFO" />
+    <logger name="io.lettuce" level="INFO" />
+    <logger name="springfox.documentation" level="INFO" />
+
+    <logger name="com.netflix.discovery" level="ERROR" />
+    <logger name="com.netflix.eureka" level="ERROR" />
+    <logger name="org.springframework.security" level="ERROR" />
+
+    <root level="DEBUG" >
+        <appender-ref ref="stdoutAppender" />
+        <!--<appender-ref ref="traceAppender" />-->
+        <appender-ref ref="debugAppender" />
+        <!--<appender-ref ref="infoAppender" />-->
+        <!--<appender-ref ref="warnAppender" />-->
+        <!--<appender-ref ref="errorAppender" />-->
     </root>
-    <!-- 指定项目中某个包,当有日志操作行为时的日志记录级别 -->
-    <!-- com.appley为根包,也就是只要是发生在这个根包下面的所有日志操作行为的权限都是DEBUG -->
-    <!-- 级别依次为【从高到低】:FATAL > ERROR > WARN > INFO > DEBUG > TRACE  -->
-    <logger name="com.yjlc.service.impl.seckill" level="DEBUG">
-        <appender-ref ref="syslog" />
-    </logger>
-</configuration>
+</configuration>

+ 64 - 0
src/main/resources/mybatis/TicketRecordMapper.xml

@@ -0,0 +1,64 @@
+<?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.ematou.wxbase.mapper.TicketRecordMapper">
+
+    <!-- 插入微信票据 -->
+    <insert id="insertRecord">
+        insert into wx_ticket_record
+        <trim prefix="(" suffix=")" suffixOverrides="," >
+            <if test="ticket != null">
+                ticket,
+            </if>
+            <if test="generationTime != null">
+                generation_time,
+            </if>
+            <if test="expireTime != null">
+                expire_time,
+            </if>
+            <if test="expiresIn != null">
+                expires_in,
+            </if>
+            <if test="timeStamp != null">
+                time_stamp,
+            </if>
+            <if test="nonceStr != null">
+                nonce_str,
+            </if>
+            <if test="sign != null">
+                sign,
+            </if>
+            <if test="reqUrl != null">
+                req_url,
+            </if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides="," >
+            <if test="ticket != null">
+                #{ticket},
+            </if>
+            <if test="generationTime != null">
+                #{generationTime},
+            </if>
+            <if test="expireTime != null">
+                #{expireTime},
+            </if>
+            <if test="expiresIn != null">
+                #{expiresIn},
+            </if>
+            <if test="timeStamp != null">
+                #{timeStamp},
+            </if>
+            <if test="nonceStr != null">
+                #{nonceStr},
+            </if>
+            <if test="sign != null">
+                #{sign},
+            </if>
+            <if test="reqUrl != null">
+                #{reqUrl},
+            </if>
+        </trim>
+    </insert>
+
+</mapper>