Browse Source

项目初次提交

Bob 8 months ago
commit
33d9edb06c

+ 12 - 0
.gitignore

@@ -0,0 +1,12 @@
+# ignore target folder
+target/
+
+# ignore IDEA files
+.idea/
+*.iml
+
+# ignore Eclipse files
+.settings/
+build/
+.classpath
+.project

+ 6 - 0
docker/Dockerfile

@@ -0,0 +1,6 @@
+FROM fabletang/jre8-alpine
+
+VOLUME /tmp
+ADD workflow_streamliner.jar app.jar
+RUN bash -c 'touch /app.jar'
+ENTRYPOINT java -Xms128m -Xmx256m -Dfile.encoding=utf-8 -Duser.timezone=GMT+8 -jar /app.jar

+ 87 - 0
pom.xml

@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.3.2.RELEASE</version>
+    </parent>
+    <groupId>cn.kdan</groupId>
+    <artifactId>workflow_streamliner</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!--<dependency>
+            <groupId>org.mybatis</groupId>
+            <artifactId>mybatis-spring</artifactId>
+            <version>2.0.7</version>
+        </dependency>-->
+        <!--mysql-->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+        <!--mybatis plus-->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>3.5.2</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-annotation</artifactId>
+            <version>3.5.2</version>
+            <scope>compile</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.sun.mail</groupId>
+            <artifactId>jakarta.mail</artifactId>
+            <version>1.6.7</version>
+        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>org.junit.jupiter</groupId>-->
+<!--            <artifactId>junit-jupiter-api</artifactId>-->
+<!--        </dependency>-->
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.8</version>
+            <scope>provided</scope>
+        </dependency>
+        <!--hutool工具包-->
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.8.2</version>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <finalName>${artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 18 - 0
src/main/java/cn/kdan/WorkflowStreamlinerApplication.java

@@ -0,0 +1,18 @@
+package cn.kdan;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @author ComPDF-Bob 2024-06-11
+ **/
+@SpringBootApplication
+@MapperScan("cn.kdan.mapper")
+public class WorkflowStreamlinerApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(WorkflowStreamlinerApplication.class, args);
+    }
+
+}

+ 48 - 0
src/main/java/cn/kdan/base/R.java

@@ -0,0 +1,48 @@
+package cn.kdan.base;
+
+
+import cn.hutool.http.HttpStatus;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+/**
+ * 请求统一返回对象
+ * @author wph
+ */
+@Data
+@AllArgsConstructor
+public class R<T> {
+
+    private String code;
+    private String msg;
+    private T data;
+
+    public static <T> R<T> ok() {
+        return ok(null);
+    }
+
+    public static <T> R<T> ok(T data) {
+        return ok("success", data);
+    }
+
+    public static <T> R<T> ok(String msg, T data) {
+        return ok(HttpStatus.HTTP_OK + "", msg, data);
+    }
+
+    public static <T> R<T> ok(String code, String msg) {
+        return new R<>(code, msg, null);
+    }
+
+    public static <T> R<T> ok(String code, String msg, T data) {
+        return new R<>(code, msg, data);
+    }
+
+    public static <T> R<T> error(String code, String msg) {
+        return error(code, msg, null);
+    }
+
+    public static <T> R<T> error(String code, String msg, T data) {
+        return new R<>(code, msg, data);
+    }
+
+}

+ 28 - 0
src/main/java/cn/kdan/controller/WorkflowStreamLinerController.java

@@ -0,0 +1,28 @@
+package cn.kdan.controller;
+
+import cn.kdan.base.R;
+import cn.kdan.service.UsersService;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @author Bob 2024-06-13
+ */
+@RestController
+@RequestMapping("/v1/workflowStreamLiner")
+public class WorkflowStreamLinerController {
+
+    private final UsersService usersService;
+
+    public WorkflowStreamLinerController(UsersService usersService) {
+        this.usersService = usersService;
+    }
+
+    /**
+     * 检查收件箱
+     */
+    @PostMapping("/checkInbox")
+    public R<?> checkInbox() {
+        return R.ok(usersService.checkInbox());
+    }
+
+}

+ 173 - 0
src/main/java/cn/kdan/entity/Users.java

@@ -0,0 +1,173 @@
+package cn.kdan.entity;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 官网用户信息
+ * @TableName users
+ */
+@Data
+public class Users implements Serializable {
+    /**
+     * 
+     */
+    private Integer id;
+
+    /**
+     * 用户全名
+     */
+    private String fullName;
+
+    /**
+     * 用户邮箱
+     */
+    private String email;
+
+    /**
+     * 用户标识:1=正常注册 2=新增订单 3=新增授权码
+     */
+    private Integer flag;
+
+    /**
+     * 用户类型 1:免费用户 2:试用用户 3:saas用户 4:SDK用户 5:saas和SDK用户 6:SaaS试用用户
+     */
+    private Integer type;
+
+    /**
+     * 密码
+     */
+    private String password;
+
+    /**
+     * 订单数量
+     */
+    private Integer orderNum;
+
+    /**
+     * 消费金额
+     */
+    private BigDecimal orderAmount;
+
+    /**
+     * 登录次数
+     */
+    private Integer loginTimes;
+
+    /**
+     * 1:SDK 2:SaaS
+     */
+    private Integer source;
+
+    /**
+     * 1:没有验证 2:通过验证
+     */
+    private Integer isVerify;
+
+    /**
+     * 1:NO 2:YES
+     */
+    private Integer hasSeenManual;
+
+    /**
+     * 1:NO 2:YES
+     */
+    private Integer isDeleted;
+
+    /**
+     * 
+     */
+    private Date createdAt;
+
+    /**
+     * 
+     */
+    private Date updatedAt;
+
+    /**
+     * 用户邮箱地址状态:0、正常;1、邮件已屏蔽;2、找不到地址
+     */
+    private Integer emailStatus;
+
+    private static final long serialVersionUID = 1L;
+
+    @Override
+    public boolean equals(Object that) {
+        if (this == that) {
+            return true;
+        }
+        if (that == null) {
+            return false;
+        }
+        if (getClass() != that.getClass()) {
+            return false;
+        }
+        Users other = (Users) that;
+        return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
+            && (this.getFullName() == null ? other.getFullName() == null : this.getFullName().equals(other.getFullName()))
+            && (this.getEmail() == null ? other.getEmail() == null : this.getEmail().equals(other.getEmail()))
+            && (this.getFlag() == null ? other.getFlag() == null : this.getFlag().equals(other.getFlag()))
+            && (this.getType() == null ? other.getType() == null : this.getType().equals(other.getType()))
+            && (this.getPassword() == null ? other.getPassword() == null : this.getPassword().equals(other.getPassword()))
+            && (this.getOrderNum() == null ? other.getOrderNum() == null : this.getOrderNum().equals(other.getOrderNum()))
+            && (this.getOrderAmount() == null ? other.getOrderAmount() == null : this.getOrderAmount().equals(other.getOrderAmount()))
+            && (this.getLoginTimes() == null ? other.getLoginTimes() == null : this.getLoginTimes().equals(other.getLoginTimes()))
+            && (this.getSource() == null ? other.getSource() == null : this.getSource().equals(other.getSource()))
+            && (this.getIsVerify() == null ? other.getIsVerify() == null : this.getIsVerify().equals(other.getIsVerify()))
+            && (this.getHasSeenManual() == null ? other.getHasSeenManual() == null : this.getHasSeenManual().equals(other.getHasSeenManual()))
+            && (this.getIsDeleted() == null ? other.getIsDeleted() == null : this.getIsDeleted().equals(other.getIsDeleted()))
+            && (this.getCreatedAt() == null ? other.getCreatedAt() == null : this.getCreatedAt().equals(other.getCreatedAt()))
+            && (this.getUpdatedAt() == null ? other.getUpdatedAt() == null : this.getUpdatedAt().equals(other.getUpdatedAt()));
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
+        result = prime * result + ((getFullName() == null) ? 0 : getFullName().hashCode());
+        result = prime * result + ((getEmail() == null) ? 0 : getEmail().hashCode());
+        result = prime * result + ((getFlag() == null) ? 0 : getFlag().hashCode());
+        result = prime * result + ((getType() == null) ? 0 : getType().hashCode());
+        result = prime * result + ((getPassword() == null) ? 0 : getPassword().hashCode());
+        result = prime * result + ((getOrderNum() == null) ? 0 : getOrderNum().hashCode());
+        result = prime * result + ((getOrderAmount() == null) ? 0 : getOrderAmount().hashCode());
+        result = prime * result + ((getLoginTimes() == null) ? 0 : getLoginTimes().hashCode());
+        result = prime * result + ((getSource() == null) ? 0 : getSource().hashCode());
+        result = prime * result + ((getIsVerify() == null) ? 0 : getIsVerify().hashCode());
+        result = prime * result + ((getHasSeenManual() == null) ? 0 : getHasSeenManual().hashCode());
+        result = prime * result + ((getIsDeleted() == null) ? 0 : getIsDeleted().hashCode());
+        result = prime * result + ((getCreatedAt() == null) ? 0 : getCreatedAt().hashCode());
+        result = prime * result + ((getUpdatedAt() == null) ? 0 : getUpdatedAt().hashCode());
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append(" [");
+        sb.append("Hash = ").append(hashCode());
+        sb.append(", id=").append(id);
+        sb.append(", fullName=").append(fullName);
+        sb.append(", email=").append(email);
+        sb.append(", flag=").append(flag);
+        sb.append(", type=").append(type);
+        sb.append(", password=").append(password);
+        sb.append(", orderNum=").append(orderNum);
+        sb.append(", orderAmount=").append(orderAmount);
+        sb.append(", loginTimes=").append(loginTimes);
+        sb.append(", source=").append(source);
+        sb.append(", isVerify=").append(isVerify);
+        sb.append(", hasSeenManual=").append(hasSeenManual);
+        sb.append(", isDeleted=").append(isDeleted);
+        sb.append(", createdAt=").append(createdAt);
+        sb.append(", updatedAt=").append(updatedAt);
+        sb.append(", serialVersionUID=").append(serialVersionUID);
+        sb.append("]");
+        return sb.toString();
+    }
+}

+ 16 - 0
src/main/java/cn/kdan/mapper/UsersMapper.java

@@ -0,0 +1,16 @@
+package cn.kdan.mapper;
+
+import cn.kdan.entity.Users;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+* @author kdan
+* @description 针对表【users(官网用户信息)】的数据库操作Mapper
+* @createDate 2024-06-13 16:56:05
+* @Entity cn.kdan.domain.Users
+*/
+public interface UsersMapper extends BaseMapper<Users> {
+
+    int updatebyEmail(Users users);
+
+}

+ 15 - 0
src/main/java/cn/kdan/service/UsersService.java

@@ -0,0 +1,15 @@
+package cn.kdan.service;
+
+import cn.hutool.json.JSONObject;
+import cn.kdan.entity.Users;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+* @author kdan
+* @description 针对表【users(官网用户信息)】的数据库操作Service
+* @createDate 2024-06-13
+*/
+public interface UsersService extends IService<Users> {
+
+    JSONObject checkInbox();
+}

+ 125 - 0
src/main/java/cn/kdan/service/impl/UsersServiceImpl.java

@@ -0,0 +1,125 @@
+package cn.kdan.service.impl;
+
+import cn.hutool.json.JSONObject;
+import cn.kdan.entity.Users;
+import cn.kdan.service.UsersService;
+import cn.kdan.mapper.UsersMapper;
+import cn.kdan.utils.EmailUtil;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import javax.mail.Folder;
+import javax.mail.Message;
+import javax.mail.Session;
+import javax.mail.Store;
+import javax.mail.search.AndTerm;
+import javax.mail.search.FromStringTerm;
+import javax.mail.search.SearchTerm;
+import javax.mail.search.SubjectTerm;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+/**
+* @author kdan
+* @description 针对表【users(官网用户信息)】的数据库操作Service实现
+* @createDate 2024-06-13
+*/
+@Slf4j
+@Service
+public class UsersServiceImpl extends ServiceImpl<UsersMapper, Users> implements UsersService{
+
+    @Value("${workflow.host}")
+    private String host;
+    @Value("${workflow.port}")
+    private String port;
+    @Value("${workflow.user}")
+    private String user;
+    @Value("${workflow.appPassword}")
+    private String appPassword;
+    @Value("${workflow.blockedStatus}")
+    private String blockedStatus;
+    @Value("${workflow.notFoundStatus}")
+    private String notFoundStatus;
+
+    @Override
+    public JSONObject checkInbox() {
+        JSONObject jsonObject = new JSONObject();
+        List<String> blockedEmailList = new ArrayList<>();
+        List<String> notFoundEmailList = new ArrayList<>();
+
+        Properties properties = new Properties();
+        properties.put("mail.store.protocol", "imaps");
+        properties.put("mail.imap.host", host);
+        properties.put("mail.imap.port", port);
+        properties.put("mail.imap.starttls.enable", "true");
+        properties.put("mail.imap.ssl.trust", "*");
+        properties.put("mail.imap.ssl.enable", "true");
+        Session session = Session.getInstance(properties);
+        try {
+            // 调试模式
+//            session.setDebug(true);
+            // Connect to the store
+            Store store = session.getStore("imap");
+            // 使用应用专用密码
+            store.connect(user, appPassword);
+            // Open the inbox folder
+            Folder inbox = store.getFolder("INBOX");
+            inbox.open(Folder.READ_ONLY);
+            // Fetch messages from the inbox
+            Message[] messages = inbox.getMessages();
+            log.info("收件箱总计邮件数: {}", messages.length);
+
+            // 创建发件人和主题的搜索条件
+            SearchTerm senderTerm = new FromStringTerm("Mail Delivery Subsystem <mailer-daemon@googlemail.com>");
+//            SearchTerm senderTerm = new FromStringTerm("no-reply@pdfreaderpro1.com");
+            SearchTerm subjectTerm = new SubjectTerm("Delivery Status Notification (Failure)");
+            SearchTerm searchTerm = new AndTerm(senderTerm, subjectTerm);
+            // 搜索匹配的邮件
+            Message[] inboxFailureMail = inbox.search(searchTerm);
+            System.out.println("邮件发送失败反馈邮件数: " + inboxFailureMail.length);
+            // 获取收件箱失败投递邮件
+            for (int i = 0; i < inboxFailureMail.length; i++) {
+                Message message = inboxFailureMail[i];
+                log.info("Email Number {}", (i + 1));
+                System.out.println("Subject: " + message.getSubject());
+                System.out.println("From: " + message.getFrom()[0]);
+                String body = EmailUtil.getTextFromMessage(message);
+                int status;
+                if (body.contains(blockedStatus)) {
+                    status = 1;
+                    body = body.substring(body.indexOf(blockedStatus));
+                } else if (body.contains(notFoundStatus)) {
+                    status = 2;
+                    body = body.substring(body.indexOf(notFoundStatus));
+                } else {
+                    log.warn("未知的失败邮件,邮件内容:{}", body);
+                    continue;
+                }
+                String targetEmail = EmailUtil.extractTargetEmail(body);
+                log.info("目标邮箱:{}", targetEmail);
+                if (status == 1) {
+                    blockedEmailList.add(targetEmail);
+                } else {
+                    notFoundEmailList.add(targetEmail);
+                }
+                // 更新数据库状态
+                Users users = new Users();
+                users.setEmail(targetEmail);
+                users.setEmailStatus(status);
+                this.baseMapper.updatebyEmail(users);
+            }
+            // Close the folder and store
+            inbox.close(false);
+            store.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        jsonObject.set("已屏蔽的邮箱", blockedEmailList);
+        jsonObject.set("找不到的邮箱", notFoundEmailList);
+        return jsonObject;
+    }
+
+}

+ 71 - 0
src/main/java/cn/kdan/utils/EmailUtil.java

@@ -0,0 +1,71 @@
+package cn.kdan.utils;
+
+import cn.hutool.json.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.util.StringUtils;
+
+import javax.mail.*;
+import javax.mail.search.AndTerm;
+import javax.mail.search.FromStringTerm;
+import javax.mail.search.SearchTerm;
+import javax.mail.search.SubjectTerm;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author ComPDF-Bob 2024-06-11
+ **/
+@Slf4j
+public class EmailUtil {
+
+    /**
+     * 获取邮件正文
+     * @param part 邮件信息
+     * @return 正文
+     * @throws MessagingException
+     * @throws IOException
+     */
+    public static String getTextFromMessage(Part part) throws MessagingException, IOException {
+        if (part.isMimeType("text/plain")) {
+            return (String) part.getContent();
+        } else if (part.isMimeType("text/html")) {
+            // 如果你想要获取 HTML 内容,可以在这里处理
+            return (String) part.getContent();
+        } else if (part.isMimeType("multipart/*")) {
+            Multipart multipart = (Multipart) part.getContent();
+            StringBuilder result = new StringBuilder();
+            for (int i = 0; i < multipart.getCount(); i++) {
+                BodyPart bodyPart = multipart.getBodyPart(i);
+                String partText = getTextFromMessage(bodyPart);
+                if (partText != null && !partText.isEmpty()) {
+                    result.append(partText);
+                }
+            }
+            return result.toString();
+        } else if (part.isMimeType("message/rfc822")) {
+            // 如果 MIME 类型是 "message/rfc822",这意味着嵌套的邮件
+            return getTextFromMessage((Part) part.getContent());
+        }
+        return "";
+    }
+
+    /**
+     * 从邮件正文中提取目标邮箱地址
+     *
+     * @param body 邮件正文
+     * @return 目标邮箱地址
+     */
+    public static String extractTargetEmail(String body) {
+        Pattern pattern = Pattern.compile("([\\w.-]+@[\\w.-]+\\.[\\w]+)");
+        Matcher matcher = pattern.matcher(body);
+        if (matcher.find()) {
+            return matcher.group(1);
+        }
+        return "";
+    }
+}

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

@@ -0,0 +1,41 @@
+server:
+  port: 8974
+spring:
+  application:
+    name: workflow_streamliner
+  jackson:
+    date-format: yyyy-MM-dd HH:mm:ss
+    time-zone: GMT+8
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://${DB_URL:139.196.160.101:3306/ComPDF_test}?autoReconnect=true&&useSSL=false
+    username: ${DB_USERNAME:debian-sys-maint}
+    password: ${DB_PASSWORD:tRF4SWujyo6rZ4Qm}
+    hikari:
+      # 最小空闲连接,默认值10
+      minimum-idle: 10
+      # 最大连接数
+      maximum-pool-size: 20
+      # 空闲连接超时时间
+      idle-timeout: 500000
+      # 连接最大存活时间
+      max-lifetime: 540000
+      # 连接超时时间
+      connection-timeout: 60000
+
+mybatis-plus:
+  mapper-locations: classpath:/mapper/*.xml
+  type-aliases-package: cn.kdan
+  configuration:
+    map-underscore-to-camel-case: true
+
+workflow:
+#  host: ${GMAIL_HOST:smtp.gmail.com}
+  host: ${GMAIL_HOST:imappro.zoho.com}
+  port: ${GMAIL_PORT:993}
+#  user: ${GMAIL_USER:liubo@kdanmobile.com}
+#  appPassword: ${GMAIL_APP_PASSWORD:faan zxke icel jjor}
+  user: ${USER:news@compdf.com}
+  appPassword: ${APP_PASSWORD:Kd@n3131660}
+  blockedStatus: ${BLOCKED_STATUS:邮件已屏蔽}
+  notFoundStatus: ${NOT_FOUND_STATUS:找不到地址}

+ 85 - 0
src/main/resources/logback-spring.xml

@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="60 seconds">
+    <!-- 引入spirng boot默认的logback配置文件 -->
+    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
+
+    <springProperty scop="context" name="spring.application.name" source="spring.application.name" defaultValue=""/>
+    <!--日志存放路径-->
+    <property name="log.path" value="/home/kdan/logs/${spring.application.name}"/>
+    <property name="log.pattern"
+              value="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %-4relative [%15.15(%thread)] %-40.40(%logger{40}) : %msg%n"/>
+    <!-- 控制台输出 -->
+    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+        </encoder>
+    </appender>
+
+    <!--debug日志-->
+    <appender name="debug_log" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!--日志文件路径和名称-->
+        <File>${log.path}/info.log</File>
+
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>ERROR</level>
+            <!-- 如果命中ERROR就不记录这条日志 -->
+            <onMatch>DENY</onMatch>
+            <!-- 如果没有命中记录 -->
+            <onMismatch>ACCEPT</onMismatch>
+        </filter>
+
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${log.path}/info.%d.%i.log</fileNamePattern>
+            <!-- 每个日志文件到10mb的时候开始切分,最多保留30天,但最大到20GB,哪怕没到30天也要删除多余的日志 -->
+            <maxHistory>7</maxHistory>
+            <totalSizeCap>5GB</totalSizeCap>
+            <maxFileSize>10MB</maxFileSize>
+        </rollingPolicy>
+        <!--编码器-->
+        <encoder>
+            <!-- pattern节点,用来设置日志的输入格式 ps:日志文件中没有设置颜色,否则颜色部分会有ESC[0:39em等乱码-->
+            <pattern>${log.pattern}</pattern>
+            <!-- 记录日志的编码:此处设置字符集 - -->
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+
+    <!--错误日志-->
+    <appender name="error_log" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!--日志文件路径和名称-->
+        <File>${log.path}/error.log</File>
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <!-- 低于ERROR级别的日志(debug,info)将被拒绝,等于或者高于ERROR的级别将相应NEUTRAL -->
+            <level>ERROR</level>
+        </filter>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <!-- 每产生一个日志文件,该日志文件的保存期限为30天, ps:maxHistory的单位是根据fileNamePattern中的翻转策略自动推算出来的,例如上面选用了yyyy-MM-dd,则单位为天
+            如果上面选用了yyyy-MM,则单位为月,另外上面的单位默认为yyyy-MM-dd-->
+            <fileNamePattern>${log.path}/error.%d.%i.log</fileNamePattern>
+            <maxHistory>7</maxHistory>
+            <!-- 每个日志文件到10mb的时候开始切分,最多保留30天,但最大到20GB,哪怕没到30天也要删除多余的日志 -->
+            <totalSizeCap>5GB</totalSizeCap>
+            <!-- maxFileSize:这是活动文件的大小,默认值是10MB-->
+            <maxFileSize>10MB</maxFileSize>
+        </rollingPolicy>
+        <!--编码器-->
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+
+    <!-- 系统模块日志级别控制  -->
+    <logger name="cn.kdan.mapper" level="debug" additivity="false">
+        <appender-ref ref="console"/>
+        <appender-ref ref="debug_log"/>
+        <appender-ref ref="error_log"/>
+    </logger>
+
+    <root level="INFO">
+        <appender-ref ref="console"/>
+        <appender-ref ref="debug_log"/>
+        <appender-ref ref="error_log"/>
+    </root>
+
+</configuration>

+ 37 - 0
src/main/resources/mapper/UsersMapper.xml

@@ -0,0 +1,37 @@
+<?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="cn.kdan.mapper.UsersMapper">
+
+    <resultMap id="BaseResultMap" type="cn.kdan.entity.Users">
+        <id property="id" column="id" jdbcType="INTEGER"/>
+        <result property="fullName" column="full_name" jdbcType="VARCHAR"/>
+        <result property="email" column="email" jdbcType="VARCHAR"/>
+        <result property="flag" column="flag" jdbcType="TINYINT"/>
+        <result property="type" column="type" jdbcType="TINYINT"/>
+        <result property="password" column="password" jdbcType="VARCHAR"/>
+        <result property="orderNum" column="order_num" jdbcType="INTEGER"/>
+        <result property="orderAmount" column="order_amount" jdbcType="DECIMAL"/>
+        <result property="loginTimes" column="login_times" jdbcType="INTEGER"/>
+        <result property="source" column="source" jdbcType="TINYINT"/>
+        <result property="isVerify" column="is_verify" jdbcType="TINYINT"/>
+        <result property="hasSeenManual" column="has_seen_manual" jdbcType="TINYINT"/>
+        <result property="isDeleted" column="is_deleted" jdbcType="TINYINT"/>
+        <result property="createdAt" column="created_at" jdbcType="TIMESTAMP"/>
+        <result property="updatedAt" column="updated_at" jdbcType="TIMESTAMP"/>
+        <result property="emailStatus" column="email_status" jdbcType="TIMESTAMP"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,full_name,email,
+        flag,type,password,
+        order_num,order_amount,login_times,
+        source,is_verify,has_seen_manual,
+        is_deleted,created_at,updated_at,email_status
+    </sql>
+
+    <update id="updatebyEmail">
+        update users set email_status = #{emailStatus}
+        where email = #{email}
+    </update>
+</mapper>