Browse Source

完成企业微信消息接受

tuonina 5 years ago
parent
commit
466cbde81e

+ 0 - 1
build.gradle

@@ -105,7 +105,6 @@ subprojects {
 
         testCompile('org.springframework.boot:spring-boot-starter-test')
         // mq
-        compile('com.fasterxml.jackson.module:jackson-module-kotlin:2.9.6')
         compile("io.reactivex.rxjava2:rxjava:$rxJavaVersion")
         
         compile("com.belerweb:pinyin4j:$pinyin4j_version")

+ 5 - 5
settings.gradle

@@ -1,9 +1,9 @@
 rootProject.name = 'tuon-framework'
-include 'zen-core'
-include 'zen-api'
-include 'zen-web'
-include 'cloud-bus'
-include 'fastdfs-client'
+//include 'zen-core'
+//include 'zen-api'
+//include 'zen-web'
+//include 'cloud-bus'
+//include 'fastdfs-client'
 include 'tuon-sign'
 include 'tuon-core'
 include 'tuon-web'

+ 1 - 0
tuon-core/build.gradle

@@ -15,4 +15,5 @@ dependencies {
     compile("com.baomidou:mybatis-plus-boot-starter:$mybatisPlusVersion")
     compile 'org.springframework.session:spring-session-data-redis'
     compile ("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.9.9")
+    compile('com.fasterxml.jackson.module:jackson-module-kotlin:2.9.9')
 }

+ 31 - 0
tuon-core/src/main/java/cn/tonyandmoney/tuon/core/error/ControllerExceptionHandler.java

@@ -0,0 +1,31 @@
+package cn.tonyandmoney.tuon.core.error;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+/**
+ * 全局的异常捕获
+ */
+@ControllerAdvice
+public class ControllerExceptionHandler {
+
+    private static final Logger logger = LoggerFactory.getLogger(ControllerExceptionHandler.class.getSimpleName());
+
+    /**
+     * 未知的运行时异常
+     */
+    @ExceptionHandler(RuntimeException.class)
+    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+    @ResponseBody
+    public BaseResp serverError(RuntimeException ex) {
+        logger.warn("server error: ", ex);
+        return BaseResp.error(ex);
+
+    }
+
+}

+ 42 - 0
tuon-core/src/main/java/cn/tonyandmoney/tuon/core/utils/DateUtils.java

@@ -0,0 +1,42 @@
+package cn.tonyandmoney.tuon.core.utils;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * 日期工具类
+ */
+public class DateUtils {
+
+    /**
+     * 日期格式
+     */
+    public static final String F_YYYYMMDD = "yyyy-MM-dd";
+
+    /**
+     * 获取当天的日期
+     *
+     * @return
+     */
+    public static Date today() {
+        Calendar calendar = Calendar.getInstance(Locale.CHINA);
+        return calendar.getTime();
+    }
+
+
+    /**
+     * 格式化日期
+     *
+     * @param date    日期
+     * @param pattern 模式
+     * @return 日期字符串
+     */
+    public static String format(Date date, String pattern) {
+        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern, Locale.CHINA);
+        return dateFormat.format(date);
+    }
+
+
+}

+ 35 - 0
tuon-core/src/main/kotlin/cn/tonyandmoney/tuon/core/config/CustomCoreConfiguration.kt

@@ -3,13 +3,19 @@ package cn.tonyandmoney.tuon.core.config
 import cn.tonyandmoney.tuon.core.cros.GlobalCrosFilter
 import cn.tonyandmoney.tuon.core.cros.GlobalWebCrosFilter
 import cn.tonyandmoney.tuon.core.properties.CustomConfigProperties
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer
+import com.fasterxml.jackson.module.kotlin.registerKotlinModule
 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
 import org.springframework.boot.context.properties.EnableConfigurationProperties
 import org.springframework.context.annotation.Bean
 import org.springframework.context.annotation.Configuration
+import org.springframework.context.annotation.Primary
+import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder
 import org.springframework.web.server.WebFilter
 import reactor.core.publisher.Flux
+import java.text.SimpleDateFormat
 
 
 /**
@@ -33,5 +39,34 @@ class CustomCoreConfiguration {
         return GlobalWebCrosFilter()
     }
 
+    @Bean("xmlObjectMapper")
+    fun xmlObjectMapper(): ObjectMapper {
+        return Jackson2ObjectMapperBuilder.xml().build()
+    }
+
+
+    @Bean
+    @Primary
+    fun builder(): Jackson2ObjectMapperBuilder {
+        return Jackson2ObjectMapperBuilder().apply {
+            serializerByType(java.lang.Long::class.java, ToStringSerializer.instance)
+            serializerByType(java.lang.Long.TYPE, ToStringSerializer.instance)
+            // date
+            dateFormat(SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))
+            timeZone("GMT+8")
+        }
+    }
+
+    /**
+     * 注册Kotlin的Module
+     */
+    @Bean
+    @Primary
+    fun objectMapper(): ObjectMapper {
+        val mapper: ObjectMapper = builder().build()
+        mapper.registerKotlinModule()
+        return mapper
+    }
+
 
 }

+ 3 - 22
tuon-core/src/main/kotlin/cn/tonyandmoney/tuon/core/config/CustomWebMvcConfiguration.kt

@@ -2,18 +2,15 @@ package cn.tonyandmoney.tuon.core.config
 
 import cn.tonyandmoney.tuon.core.properties.CustomConfigProperties
 import com.fasterxml.jackson.databind.ObjectMapper
-import com.fasterxml.jackson.databind.ser.std.ToStringSerializer
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
 import org.springframework.boot.context.properties.EnableConfigurationProperties
 import org.springframework.context.annotation.Bean
 import org.springframework.context.annotation.Configuration
-import org.springframework.context.annotation.Primary
 import org.springframework.http.codec.ServerCodecConfigurer
 import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder
 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
 import org.springframework.web.reactive.config.ResourceHandlerRegistry
 import org.springframework.web.reactive.config.WebFluxConfigurationSupport
-import java.text.SimpleDateFormat
 
 /**
  * Created by niantuo on 2018/9/20.
@@ -44,34 +41,18 @@ class CustomWebMvcConfiguration : WebFluxConfigurationSupport() {
 
 
     @Bean(CONVERTER_NAME)
-    fun getConverter(): MappingJackson2HttpMessageConverter {
+    fun getConverter(objectMapper: ObjectMapper): MappingJackson2HttpMessageConverter {
         return MappingJackson2HttpMessageConverter().apply {
-            this.objectMapper = builder().build()
+            this.objectMapper = objectMapper
         }
     }
 
     @Bean
-    fun xmlConverter():MappingJackson2HttpMessageConverter{
+    fun xmlConverter(): MappingJackson2HttpMessageConverter {
         return MappingJackson2HttpMessageConverter().apply {
             this.objectMapper = Jackson2ObjectMapperBuilder.xml().build()
         }
-
     }
 
-    @Bean("xmlObjectMapper")
-    fun xmlObjectMapper():ObjectMapper{
-        return Jackson2ObjectMapperBuilder.xml().build()
-    }
 
-    @Bean
-    @Primary
-    fun builder(): Jackson2ObjectMapperBuilder {
-        return Jackson2ObjectMapperBuilder().apply {
-            serializerByType(java.lang.Long::class.java, ToStringSerializer.instance)
-            serializerByType(java.lang.Long.TYPE, ToStringSerializer.instance)
-            // date
-            dateFormat(SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))
-            timeZone("GMT+8")
-        }
-    }
 }

+ 20 - 9
tuon-qywx/src/main/java/cn/tonyandmoney/tuon/qywx/aes/WXBizMsgCrypt.java

@@ -6,6 +6,10 @@
  * 针对org.apache.commons.codec.binary.Base64,
  * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本)
  * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi
+ * <p>
+ * 针对org.apache.commons.codec.binary.Base64,
+ * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本)
+ * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi
  */
 
 // ------------------------------------------------------------------------
@@ -17,15 +21,14 @@
  */
 package cn.tonyandmoney.tuon.qywx.aes;
 
-import java.nio.charset.Charset;
-import java.util.Arrays;
-import java.util.Random;
+import org.apache.commons.codec.binary.Base64;
 
 import javax.crypto.Cipher;
 import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
-
-import org.apache.commons.codec.binary.Base64;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Random;
 
 /**
  * 提供接收和推送给企业微信消息的加解密接口(UTF8编码的字符串).
@@ -88,10 +91,10 @@ public class WXBizMsgCrypt {
     }
 
     // 随机生成16位字符串
-    String getRandomStr() {
+    public static String getRandomStr() {
         String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
         Random random = new Random();
-        StringBuffer sb = new StringBuffer();
+        StringBuilder sb = new StringBuilder();
         for (int i = 0; i < 16; i++) {
             int number = random.nextInt(base.length());
             sb.append(base.charAt(number));
@@ -226,8 +229,7 @@ public class WXBizMsgCrypt {
 
         // System.out.println("发送给平台的签名是: " + signature[1].toString());
         // 生成发送的xml
-        String result = XMLParse.generate(encrypt, signature, timeStamp, nonce);
-        return result;
+        return XMLParse.generate(encrypt, signature, timeStamp, nonce);
     }
 
     /**
@@ -267,6 +269,15 @@ public class WXBizMsgCrypt {
         return decrypt(encrypt[1].toString());
     }
 
+    /**
+     * 一定要先得到内容,适合多应用
+     * @param msgSignature
+     * @param timeStamp
+     * @param nonce
+     * @param encrypt
+     * @return
+     * @throws AesException
+     */
     public String decryptMsg(String msgSignature, String timeStamp, String nonce, String encrypt) throws AesException {
         // 验证安全签名
         String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt);

+ 53 - 15
tuon-qywx/src/main/java/cn/tonyandmoney/tuon/qywx/bean/WxMsg.java

@@ -5,21 +5,52 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 
 /**
  * @Classname WxMsg
- * @Description TODO
+ * @Description 企业微信消息的消息实体类
  * @Date 2019/8/26 21:25
  * @Created by Administrator
  */
 public class WxMsg {
     @JsonProperty("ToUserName")
     private String ToUserName;
-    @JsonProperty("Encrypt")
-    private String Encrypt;
-    @JsonProperty("AgentID")
-    private String AgentID;
-    @JsonProperty("MsgId")
-    private String MsgId;
     @JsonProperty("FromUserName")
     private String FromUserName;
+    @JsonProperty("CreateTime")
+    private String CreateTime;
+    @JsonProperty("MsgType")
+    private String MsgType;
+    @JsonProperty("Content")
+    private String Content;
+    @JsonProperty("MsgId")
+    private String MsgId;
+    @JsonProperty("AgentID")
+    private String AgentID;
+
+    @JsonIgnore
+    public String getCreateTime() {
+        return CreateTime;
+    }
+
+    public void setCreateTime(String createTime) {
+        CreateTime = createTime;
+    }
+
+    @JsonIgnore
+    public String getMsgType() {
+        return MsgType;
+    }
+
+    public void setMsgType(String msgType) {
+        MsgType = msgType;
+    }
+
+    @JsonIgnore
+    public String getContent() {
+        return Content;
+    }
+
+    public void setContent(String content) {
+        Content = content;
+    }
 
     public void setFromUserName(String fromUserName) {
         FromUserName = fromUserName;
@@ -28,10 +59,12 @@ public class WxMsg {
     public void setMsgId(String msgId) {
         MsgId = msgId;
     }
+
     @JsonIgnore
     public String getFromUserName() {
         return FromUserName;
     }
+
     @JsonIgnore
     public String getMsgId() {
         return MsgId;
@@ -46,14 +79,6 @@ public class WxMsg {
         ToUserName = toUserName;
     }
 
-    @JsonIgnore
-    public String getEncrypt() {
-        return Encrypt;
-    }
-
-    public void setEncrypt(String encrypt) {
-        Encrypt = encrypt;
-    }
 
     @JsonIgnore
     public String getAgentID() {
@@ -63,4 +88,17 @@ public class WxMsg {
     public void setAgentID(String agentID) {
         AgentID = agentID;
     }
+
+    @Override
+    public String toString() {
+        return "\nWxMsg{" +
+                "ToUserName: " + ToUserName + ",\n" +
+                "FromUserName:" + FromUserName + ",\n" +
+                "CreateTime:" + CreateTime + ",\n" +
+                "MsgType:" + MsgType + ",\n" +
+                "Content:" + Content + ",\n" +
+                "MsgId:" + MsgId + ",\n" +
+                "AgentID:" + AgentID  +
+                "}";
+    }
 }

+ 41 - 0
tuon-qywx/src/main/kotlin/cn/tonyandmoney/tuon/qywx/controller/DutyController.kt

@@ -0,0 +1,41 @@
+package cn.tonyandmoney.tuon.qywx.controller
+
+import cn.tonyandmoney.tuon.core.utils.DateUtils
+import cn.tonyandmoney.tuon.qywx.entity.TDuty
+import cn.tonyandmoney.tuon.qywx.service.IDutyService
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.web.bind.annotation.*
+import reactor.core.publisher.Mono
+import java.util.*
+
+/**
+ * 值班信息接口
+ */
+@RestController
+@RequestMapping("/duty")
+class DutyController {
+
+    @Autowired
+    private lateinit var dutyService: IDutyService
+
+
+    /**
+     * 单个添加值班信息
+     */
+    @PostMapping
+    fun addDuty(@RequestBody duty: TDuty): Mono<Void> {
+        return dutyService.addDuty(duty)
+    }
+
+
+    /**
+     * 根据日期查询值班信息,如果没有传递日期,则默认为当天
+     * 未进行分页
+     */
+    @GetMapping
+    fun queryDutyByDate(@RequestParam("date", required = false) date: Date?): Mono<List<TDuty>> {
+        return dutyService.queryByDate(date ?: DateUtils.today())
+    }
+
+
+}

+ 72 - 18
tuon-qywx/src/main/kotlin/cn/tonyandmoney/tuon/qywx/controller/QywxController.kt

@@ -6,11 +6,13 @@ import cn.tonyandmoney.tuon.core.error.OpException
 import cn.tonyandmoney.tuon.core.error.SessionNoUserException
 import cn.tonyandmoney.tuon.core.session.SessionUtils
 import cn.tonyandmoney.tuon.core.user.IUser
+import cn.tonyandmoney.tuon.core.utils.DateUtils
 import cn.tonyandmoney.tuon.qywx.QywxProperties
 import cn.tonyandmoney.tuon.qywx.WxErrorCode
 import cn.tonyandmoney.tuon.qywx.aes.WXBizMsgCrypt
 import cn.tonyandmoney.tuon.qywx.bean.WxMsg
 import cn.tonyandmoney.tuon.qywx.bean.WxUser
+import cn.tonyandmoney.tuon.qywx.service.IDutyService
 import cn.tonyandmoney.tuon.qywx.service.IQywxService
 import com.fasterxml.jackson.databind.ObjectMapper
 import org.slf4j.LoggerFactory
@@ -18,13 +20,19 @@ import org.slf4j.MarkerFactory
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.beans.factory.annotation.Qualifier
 import org.springframework.core.io.buffer.DataBufferUtils
+import org.springframework.http.MediaType.APPLICATION_XML_VALUE
 import org.springframework.http.server.reactive.ServerHttpRequest
-import org.springframework.stereotype.Controller
 import org.springframework.web.bind.annotation.*
 import org.springframework.web.server.ServerWebExchange
 import reactor.core.publisher.Mono
 
-@Controller
+/**
+ * 企业微信相关的接口
+ * 1、根据临时code获取用户身份信息
+ * 2、消息接受接口
+ * 3、消息接受验证接口
+ */
+@RestController
 @RequestMapping("/qywx")
 class QywxController {
 
@@ -39,12 +47,19 @@ class QywxController {
     private lateinit var properties: QywxProperties
     @Autowired
     private lateinit var wxBizMsgCrypt: WXBizMsgCrypt
+    @Autowired
+    private lateinit var dutyService: IDutyService
+
     @Autowired
     @Qualifier("xmlObjectMapper")
     private lateinit var objectMapper: ObjectMapper
 
+    /**
+     * @param code 凭据
+     * 根据授code获取用户身份信息,先判断session中是否有该用户的身份信息,
+     * 如果有,则直接返回session身份信息,如果code为空,则只判断session中的数据
+     */
     @GetMapping("/user")
-    @ResponseBody
     fun getUserInfo(@RequestParam("code", required = false) code: String?,
                     @RequestParam("agentId") agentId: String,
                     exchange: ServerWebExchange): Mono<BaseResp<IUser>> {
@@ -67,14 +82,14 @@ class QywxController {
                         Mono.just(BaseResp.error(it))
                     }
                 }
-
-
     }
 
+
     /**
      * 接收消息,返回的数据类型
+     * 如果收到值班关键词,则查询当天的值班人员,返回
      */
-    @PostMapping("/config/message", produces = ["application/xml;charset=UTF-8"])
+    @PostMapping("/config/message", produces = [APPLICATION_XML_VALUE])
     fun configUserMessage(@RequestParam("msg_signature") signature: String,
                           @RequestParam("timestamp") timestamp: String,
                           @RequestParam("nonce") nonce: String,
@@ -82,38 +97,77 @@ class QywxController {
 
         return DataBufferUtils.join(request.body)
                 .flatMap { dataBuffer ->
-                    Mono.create<String> {
+                    Mono.create<WxMsg> {
                         val bytes = ByteArray(dataBuffer.readableByteCount())
                         dataBuffer.read(bytes)
+                        val content = wxBizMsgCrypt.DecryptMsg(signature, timestamp, nonce, String(bytes))
+                        val wxMsg = objectMapper.readValue<WxMsg>(content, WxMsg::class.java)
 
-                        val wxMsg = objectMapper.readValue<WxMsg>(bytes, WxMsg::class.java)
-                        val content = wxBizMsgCrypt.decryptMsg(signature, timestamp, nonce, wxMsg.encrypt)
-                        logger.info(msgMarker, "content:{}", content)
-                        val resp = ""
-                        if ("值班" == content) {
+                        logger.info(msgMarker, "wxMsg :{}", wxMsg)
+                        it.success(wxMsg)
+                    }
+                }
+                .flatMap<String> { wxMsg ->
+                    if ("值班" == wxMsg.content) {
+                        getEncryptDutyMsg(wxMsg)
+                    } else {
+                        Mono.empty()
+                    }
+                }
 
-                        } else {
+    }
 
+    /**
+     * 获取今日值班信息,并按照企业微信回复消息格式进行封装,加密
+     */
+    private fun getEncryptDutyMsg(wxMsg: WxMsg): Mono<String> {
+        return dutyService.queryByDate(DateUtils.today())
+                .flatMap { list ->
+                    Mono.create<String> {
+                        val time = System.currentTimeMillis().toString()
+                        val respMsg = WxMsg().apply {
+                            fromUserName = wxMsg.toUserName
+                            toUserName = wxMsg.fromUserName
+                            msgType = "text"
+                            content = "今日值班人员:${list.map { duty -> duty.userName }.joinToString(",")}"
+                            createTime = time
                         }
-                        Mono.just(resp)
+                        val respText = objectMapper.writeValueAsString(respMsg)
+                        logger.info(msgMarker, "reply msg: {}", respText)
+                        val resp = wxBizMsgCrypt.EncryptMsg(respText, time, WXBizMsgCrypt.getRandomStr())
+                        it.success(resp)
                     }
                 }
-
     }
 
     /**
-     * 验证URL
+     * 验证URL接口,当在企业微信后台,添加消息接受接口的时候,会调用改接口做验证
      */
-    @GetMapping("/config/message",produces = ["application/xml;charset=UTF-8"])
+    @GetMapping("/config/message", produces = [APPLICATION_XML_VALUE])
     fun verifySignature(@RequestParam("msg_signature") signature: String,
                         @RequestParam("timestamp") timestamp: String,
                         @RequestParam("nonce") nonce: String,
                         @RequestParam("echostr") echostr: String): Mono<String> {
         return Mono.create {
-            logger.info(msgMarker,"signature:{},timestamp:{},nonce:{},echostr:{}",signature,timestamp,nonce,echostr)
+            logger.info(msgMarker, "signature:{},timestamp:{},nonce:{},echostr:{}", signature, timestamp, nonce, echostr)
             val utils = WXBizMsgCrypt(properties.token, properties.encodingAESKey, properties.corpid)
             it.success(utils.VerifyURL(signature, timestamp, nonce, echostr))
         }
     }
 
+    /**
+     * 返回XML数据,一个测试接口
+     */
+    @PostMapping("/xml", produces = [APPLICATION_XML_VALUE])
+    fun producesXml(): Mono<String> {
+        return Mono.create {
+            val wxMsg = WxMsg().apply {
+                toUserName = "TuoNian"
+                agentID = "123"
+            }
+            it.success(objectMapper.writeValueAsString(wxMsg))
+        }
+    }
+
+
 }

+ 9 - 0
tuon-qywx/src/main/kotlin/cn/tonyandmoney/tuon/qywx/dao/IDao.kt

@@ -0,0 +1,9 @@
+package cn.tonyandmoney.tuon.qywx.dao
+
+import cn.tonyandmoney.tuon.qywx.entity.TDuty
+import com.baomidou.mybatisplus.core.mapper.BaseMapper
+import org.springframework.stereotype.Repository
+
+
+@Repository
+interface IDutyDao : BaseMapper<TDuty>

+ 34 - 0
tuon-qywx/src/main/kotlin/cn/tonyandmoney/tuon/qywx/entity/TDuty.kt

@@ -0,0 +1,34 @@
+package cn.tonyandmoney.tuon.qywx.entity
+
+import com.baomidou.mybatisplus.annotation.IdType
+import com.baomidou.mybatisplus.annotation.TableId
+import com.baomidou.mybatisplus.annotation.TableName
+import com.fasterxml.jackson.annotation.JsonFormat
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties
+import com.fasterxml.jackson.annotation.JsonInclude
+import java.util.*
+
+/**
+ * 值班表
+ * @property userId 用户ID
+ * @property userName 用户姓名
+ * @property dutyDate 值班的日期
+ */
+@TableName("t_duty")
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+data class TDuty(
+        @TableId(type = IdType.ID_WORKER)
+        var id: Long? = null,
+        var userId: String? = null,
+        var userName: String? = null,
+        @JsonFormat(pattern = "yyyy-MM-dd")
+        var dutyDate: Date? = null,
+        var createBy: String? = null,
+        @JsonFormat(pattern = "yyyy-MM-dd HH:mm")
+        var createTime: Date? = null,
+        var updateBy: String? = null,
+        @JsonFormat(pattern = "yyyy-MM-dd HH:mm")
+        var updateTime: Date? = null,
+        var remark: String? = null) {
+}

+ 21 - 0
tuon-qywx/src/main/kotlin/cn/tonyandmoney/tuon/qywx/service/IDutyService.kt

@@ -0,0 +1,21 @@
+package cn.tonyandmoney.tuon.qywx.service
+
+import cn.tonyandmoney.tuon.qywx.entity.TDuty
+import reactor.core.publisher.Mono
+import java.util.*
+
+interface IDutyService {
+
+    /**
+     * 添加值班人员
+     */
+    fun addDuty(duty:TDuty):Mono<Void>
+
+    /**
+     * 根据值班日期查询值班信息
+     */
+    fun queryByDate(date:Date):Mono<List<TDuty>>
+
+
+
+}

+ 38 - 0
tuon-qywx/src/main/kotlin/cn/tonyandmoney/tuon/qywx/service/impl/DutyServiceImpl.kt

@@ -0,0 +1,38 @@
+package cn.tonyandmoney.tuon.qywx.service.impl
+
+import cn.tonyandmoney.tuon.core.utils.DateUtils
+import cn.tonyandmoney.tuon.qywx.dao.IDutyDao
+import cn.tonyandmoney.tuon.qywx.entity.TDuty
+import cn.tonyandmoney.tuon.qywx.service.IDutyService
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.stereotype.Service
+import reactor.core.publisher.Mono
+import java.util.*
+
+/**
+ * 值班操作
+ */
+@Service
+class DutyServiceImpl : IDutyService {
+
+    @Autowired
+    private lateinit var dutyDao: IDutyDao
+
+    override fun addDuty(duty: TDuty): Mono<Void> {
+        return Mono.create {
+            duty.createTime = DateUtils.today()
+            dutyDao.insert(duty)
+            it.success()
+        }
+    }
+
+    override fun queryByDate(date: Date): Mono<List<TDuty>> {
+        return Mono.create {
+            val wrapper = QueryWrapper<TDuty>().apply {
+                eq("duty_date", DateUtils.format(date, DateUtils.F_YYYYMMDD))
+            }
+            it.success(dutyDao.selectList(wrapper))
+        }
+    }
+}

+ 2 - 0
tuon-web/src/main/kotlin/cn/tonyandmoney/tuon/web/MainApplication.kt

@@ -1,5 +1,6 @@
 package cn.tonyandmoney.tuon.web
 
+import org.mybatis.spring.annotation.MapperScan
 import org.springframework.boot.SpringApplication
 import org.springframework.boot.autoconfigure.SpringBootApplication
 import org.springframework.boot.builder.SpringApplicationBuilder
@@ -14,6 +15,7 @@ import org.springframework.session.data.redis.config.annotation.web.server.Enabl
 @EnableEurekaClient
 @EnableDiscoveryClient
 @EnableRedisWebSession
+@MapperScan(basePackages = ["cn.tonyandmoney.tuon.**.dao"])
 @SpringBootApplication(scanBasePackages = ["cn.tonyandmoney.tuon"])
 class MainApplication : SpringBootServletInitializer() {
     override fun configure(builder: SpringApplicationBuilder): SpringApplicationBuilder {

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

@@ -21,6 +21,7 @@ qywx:
 
 logging:
   path: ./logs
+  file: fw.log
 
 ---
 spring:

+ 1 - 0
tuon-web/src/main/resources/bootstrap.yml

@@ -22,6 +22,7 @@ spring:
 spring:
   profiles: dev
 
+
 eureka:
   instance:
     prefer-ip-address: true