소스 검색

Merge branch 'master' of ssh://192.168.8.213:10022/miaxis/twzd

Althars123 3 년 전
부모
커밋
d00722ba07

+ 14 - 0
pom.xml

@@ -233,6 +233,20 @@
                 <version>${feign.version}</version>
             </dependency>
 
+            <!--谷歌二维码生成-->
+            <dependency>
+                <groupId>com.google.zxing</groupId>
+                <artifactId>core</artifactId>
+                <version>3.4.0</version>
+            </dependency>
+
+            <!--hutool工具包-->
+            <dependency>
+                <groupId>cn.hutool</groupId>
+                <artifactId>hutool-all</artifactId>
+                <version>5.7.14</version>
+            </dependency>
+
         </dependencies>
     </dependencyManagement>
 

+ 11 - 0
twzd-admin/pom.xml

@@ -69,6 +69,17 @@
             <version>1.0.1</version>
         </dependency>
 
+        <!--谷歌二维码生成-->
+        <dependency>
+            <groupId>com.google.zxing</groupId>
+            <artifactId>core</artifactId>
+        </dependency>
+
+        <!--hutool工具包-->
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+        </dependency>
 
     </dependencies>
 

+ 106 - 0
twzd-admin/src/main/java/com/miaxis/system/controller/h5/QuestionInfoController.java

@@ -0,0 +1,106 @@
+package com.miaxis.system.controller.h5;
+
+import com.miaxis.common.annotation.Log;
+import com.miaxis.common.core.controller.BaseController;
+import com.miaxis.common.core.domain.Response;
+import com.miaxis.common.core.page.ResponsePageInfo;
+import com.miaxis.common.enums.BusinessTypeEnum;
+import com.miaxis.common.utils.poi.ExcelUtil;
+import com.miaxis.qustion.domain.QuestionInfo;
+import com.miaxis.qustion.service.IQuestionInfoService;
+import io.swagger.annotations.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 【题库】Controller
+ *
+ * @author miaxis
+ * @date 2021-10-20
+ */
+@RestController
+@RequestMapping("/qustion/info")
+@Api(tags={"【小程序-题库】"})
+public class QuestionInfoController extends BaseController{
+    @Autowired
+    private IQuestionInfoService questionInfoService;
+
+    /**
+     * 查询题库列表
+     */
+    @GetMapping("/list")
+    @ApiOperation("查询题库列表")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "pageNum",value = "当前页码" ,dataType = "int", paramType = "query", required = false),
+            @ApiImplicitParam(name = "pageSize",value = "每页数据量" , dataType = "int", paramType = "query", required = false),
+    })
+    public ResponsePageInfo<QuestionInfo> list(@ModelAttribute QuestionInfo questionInfo){
+        startPage();
+        List<QuestionInfo> list = questionInfoService.selectQuestionInfoList(questionInfo);
+        return toResponsePageInfo(list);
+    }
+
+//    /**
+//     * 导出题库列表
+//     */
+//    @Log(title = "题库", businessType = BusinessTypeEnum.EXPORT)
+//    @GetMapping("/export")
+//    @ApiOperation("导出题库列表Excel")
+//    public Response<String> export(@ModelAttribute QuestionInfo questionInfo){
+//        List<QuestionInfo> list = questionInfoService.selectQuestionInfoList(questionInfo);
+//        ExcelUtil<QuestionInfo> util = new ExcelUtil<QuestionInfo>(QuestionInfo.class);
+//        return util.exportExcel(list, "info");
+//    }
+
+    /**
+     * 获取题库详细信息
+     */
+    @GetMapping(value = "/{id}")
+    @ApiOperation("获取题库详细信息")
+    public Response<QuestionInfo> getInfo(
+            @ApiParam(name = "id", value = "题库参数", required = true)
+            @PathVariable("id") Long id
+    ){
+        return Response.success(questionInfoService.getById(id));
+    }
+
+    /**
+     * 新增题库
+     */
+//    @PreAuthorize("@ss.hasPermi('qustion:info:add')")
+//    @Log(title = "题库", businessType = BusinessTypeEnum.INSERT)
+//    @PostMapping
+//    @ApiOperation("新增题库")
+//    public Response<Integer> add(@RequestBody QuestionInfo questionInfo){
+//        return toResponse(questionInfoService.save(questionInfo) ? 1 : 0);
+//    }
+
+    /**
+     * 修改题库
+     */
+//    @PreAuthorize("@ss.hasPermi('qustion:info:edit')")
+//    @Log(title = "题库", businessType = BusinessTypeEnum.UPDATE)
+//    @PutMapping
+//    @ApiOperation("修改题库")
+//    public Response<Integer> edit(@RequestBody QuestionInfo questionInfo){
+//        return toResponse(questionInfoService.updateById(questionInfo) ? 1 : 0);
+//    }
+
+    /**
+     * 删除题库
+     */
+//    @PreAuthorize("@ss.hasPermi('qustion:info:remove')")
+//    @Log(title = "题库", businessType = BusinessTypeEnum.DELETE)
+//	@DeleteMapping("/{ids}")
+//    @ApiOperation("删除题库")
+//    public  Response<Integer> remove(
+//            @ApiParam(name = "ids", value = "题库ids参数", required = true)
+//            @PathVariable Long[] ids
+//    ){
+//        return toResponse(questionInfoService.removeByIds(Arrays.asList(ids)) ? 1 : 0);
+//    }
+}

+ 349 - 0
twzd-admin/src/main/java/com/miaxis/system/controller/test/TestController.java

@@ -0,0 +1,349 @@
+package com.miaxis.system.controller.test;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.extra.qrcode.QrCodeUtil;
+import cn.hutool.json.XML;
+import com.alibaba.fastjson.JSONObject;
+import com.miaxis.common.constant.Constants;
+import com.miaxis.common.core.domain.Response;
+import com.miaxis.common.utils.wx.SignUtil;
+import com.miaxis.feign.dto.WxTicket;
+import com.miaxis.feign.service.IWxMpService;
+import com.miaxis.feign.service.IWxSendService;
+import com.miaxis.wx.service.IWxGzhService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.*;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/21 14:02
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping(Constants.OPEN_PREFIX + "/wxTest")
+@Api(tags={"wx测试"})
+public class TestController {
+
+    private static final Logger log = LoggerFactory.getLogger(TestController.class);
+
+    @Autowired
+    IWxSendService wxSendService;
+
+    @Autowired
+    IWxGzhService wxGzhService;
+
+    @Autowired
+    IWxMpService wxMpService;
+
+    @Autowired
+    HttpServletRequest request;
+
+    /**
+     * 生成带参数的二维码
+     */
+    @GetMapping(value = "/generateTicket")
+    @ApiOperation("生成带参数的二维码")
+    public Response generateTicket() throws Exception{
+        String xcxMessageToken = wxGzhService.getGzhToken();
+        WxTicket wxTicket = new WxTicket();
+        wxTicket.setExpire_seconds(86400);//一天
+        wxTicket.setAction_name("QR_SCENE");
+        JSONObject jsonObject1 = new JSONObject();
+        JSONObject jsonObject2 = new JSONObject();
+        jsonObject1.put("scene_id","123");
+        jsonObject2.put("scene",jsonObject1);
+        wxTicket.setAction_info(jsonObject2);
+        String result = wxSendService.generateTicket(xcxMessageToken,wxTicket);
+        System.out.println("生成ticket:" + result);
+        JSONObject jsonStr = JSONObject.parseObject(result);
+
+        QrCodeUtil.generate(
+                jsonStr.getString("url"), //二维码内容
+                300, 300,
+                //QrConfig.create().setImg("C:\\Users\\wwl\\Desktop\\二维码\\微信图片_20211021120216.jpg")
+                FileUtil.file("/data/test/qrimg.jpg")//写出到的文件
+        );
+
+        return Response.success();
+    }
+
+
+
+    /**
+     * 处理服务器推送消息
+     * @param request
+     * @param response
+     * @return
+     */
+    @RequestMapping(value = "/notifyMsg",method = { RequestMethod.GET, RequestMethod.POST })
+    @ApiOperation("处理服务器推送消息")
+    public String checkSign(HttpServletRequest request, HttpServletResponse response) {
+        log.info("-----------进入---------");
+        try {
+            String signature = request.getParameter("signature");
+            String timestamp = request.getParameter("timestamp");
+            String nonce = request.getParameter("nonce");
+            String echostr = request.getParameter("echostr");
+            log.info("本身" + signature);
+            if(request.getMethod().equals("GET")){
+                log.info("-----------微信验签---------");
+                return SignUtil.checkSignature(signature, timestamp, nonce) == true ? echostr : null;
+            }else{
+                log.info("-----------推送消息处理---------");
+                return handlePublicMsg(request);
+            }
+        } catch (Exception e) {
+            log.error("验证公众号token失败", e);
+        }
+        return null;
+    }
+
+
+    //微信功能处理
+    public String WexHandeler(HttpServletRequest request) throws Exception {
+        try {
+            cn.hutool.json.JSONObject info = XML.toJSONObject(IOUtils.toString(request.getInputStream()));
+            log.info("info:" + info);
+            if (info.get("xml") != null) {
+                JSONObject event = (JSONObject) info.get("xml");
+                if (event.get("MsgType") != null) {
+                    String Event = (String) event.get("Event");//事件类型 关注事件还是取消关注等
+                    //如果是事件
+                    if (!StringUtils.isEmpty(Event)) try {
+                        if ("subscribe".equals(Event)) {  //带参数二维码的关注事件
+                            //关注方法
+                            String toUserName = (String) event.get("ToUserName");//开发者微信号
+                            String fromUserName = (String) event.get("FromUserName");//发送方帐号(一个OpenID)
+                            String eventKey = (String) event.get("EventKey");//事件KEY值,是一个32位无符号整数,即创建二维码时的二维码scene_id
+                            String ticket = (String) event.get("Ticket");//二维码的ticket,可用来换取二维码图片
+                            log.info(">>>>>>>>>>>>>>>>>>接受的数据为:");
+                            log.info("toUserName:" + toUserName);
+                            log.info("fromUserName:" + fromUserName);
+                            log.info("scene_id:" + eventKey);
+                            log.info("ticket:" + ticket);
+                            //解析完执行操作
+
+                        } else if ("SCAN".equals(Event)) {//扫描带参数二维码事件 用户已关注时的事件推送
+                            String toUserName = (String) event.get("ToUserName");//开发者微信号
+                            String fromUserName = (String) event.get("FromUserName");//发送方帐号(一个OpenID)
+                            String eventKey = (String) event.get("EventKey");//事件KEY值,是一个32位无符号整数,即创建二维码时的二维码scene_id
+                            String ticket = (String) event.get("Ticket");//二维码的ticket,可用来换取二维码图片
+                            log.info(">>>>>>>>>>>>>>>>>>接受的数据为:");
+                            log.info("toUserName:" + toUserName);
+                            log.info("fromUserName:" + fromUserName);
+                            log.info("scene_id:" + eventKey);
+                            log.info("ticket:" + ticket);
+                            //解析完执行操作
+
+                        } else if ("unsubscribe".equals(Event)) { //取消订阅事件
+
+                        }
+                    } catch (Exception e) {
+                        return e.getMessage();
+                    }
+                }
+            }
+        } catch (Exception e) {
+            return request.getParameter("echostr");
+        }
+        return request.getParameter("echostr");
+    }
+
+
+
+    /**
+     * 处理微信公众号请求信息
+     */
+    public String handlePublicMsg(HttpServletRequest request) throws Exception {
+        log.info("1....");
+        // 获得微信端返回的xml数据
+        InputStream is = null;
+        InputStreamReader isr = null;
+        BufferedReader br = null;
+        try {
+            is = request.getInputStream();
+            isr = new InputStreamReader(is, "utf-8");
+            br = new BufferedReader(isr);
+            log.info("2....");
+            String str = null;
+            StringBuffer returnXml= new StringBuffer();
+            while ((str = br.readLine()) != null) {
+                log.info("3....");
+                //返回的是xml数据
+                returnXml.append(str);
+            }
+//            Map<String, String> decryptMap = xmlToMap(returnXml.toString());
+            Map<String, String> decryptMap = xmlToMap(returnXml.toString());
+            log.info("-----decryptMap------"+decryptMap);
+//            // 得到公众号传来的加密信息并解密,得到的是明文xml数据
+//            String decryptXml = WXPublicUtils.decrypt(encryptMap.get("Encrypt"));
+            // 将xml数据转换为map
+            //Map<String, String> decryptMap = xmlToMap(encryptMap);
+            log.info("5....");
+
+            // 区分消息类型
+            String msgType = decryptMap.get("MsgType");
+            log.info("5.1...");
+            // 普通消息
+            if ("text".equals(msgType)) { // 文本消息
+                // todo 处理文本消息
+            } else if ("image".equals(msgType)) { // 图片消息
+                // todo 处理图片消息
+            }
+
+            // 事件推送
+            else if ("event".equals(msgType)) { // 事件消息
+                // 区分事件推送
+                String event = decryptMap.get("Event");
+                if ("subscribe".equals(event)) { // 订阅事件 或 未关注扫描二维码事件
+                    log.info("5.2...");
+                    // 返回消息时ToUserName的值与FromUserName的互换
+                    Map<String, String> returnMap = new HashMap<>();
+                    returnMap.put("ToUserName", decryptMap.get("FromUserName"));
+                    returnMap.put("FromUserName", decryptMap.get("ToUserName"));
+                    returnMap.put("CreateTime", new Date().getTime()+"");
+                    returnMap.put("MsgType", "text");
+                    returnMap.put("Content", "测试哈哈哈哈");
+                    log.info("5.2...----returnMap-----"+returnMap);
+                    String encryptMsg = mapToXml(returnMap);
+                    return encryptMsg;
+                }  else if ("unsubscribe".equals(event)) { // 取消订阅事件
+                    // todo 处理取消订阅事件
+                } else if ("SCAN".equals(event)) { // 已关注扫描二维码事件
+                    log.info("5.3...");
+                    // 返回消息时ToUserName的值与FromUserName的互换
+                    Map<String, String> returnMap = new HashMap<>();
+                    returnMap.put("ToUserName", decryptMap.get("FromUserName"));
+                    returnMap.put("FromUserName", decryptMap.get("ToUserName"));
+                    returnMap.put("CreateTime", new Date().getTime()+"");
+                    returnMap.put("MsgType", "text");
+                    returnMap.put("Content", "测试哈哈哈哈");
+                    log.info("5.3...----returnMap-----"+returnMap);
+                    String encryptMsg = mapToXml(returnMap);
+                    return encryptMsg;
+                } else if ("LOCATION".equals(event)) { // 上报地理位置事件
+                    // todo 处理上报地理位置事件
+                } else if ("CLICK".equals(event)) { // 点击菜单拉取消息时的事件推送事件
+                    // todo 处理点击菜单拉取消息时的事件推送事件
+                } else if ("VIEW".equals(event)) { // 点击菜单跳转链接时的事件推送
+                    // todo 处理点击菜单跳转链接时的事件推送
+                }
+            }
+        } catch (Exception e) {
+            log.error("处理微信公众号请求信息,失败", e);
+        }
+        return null;
+    }
+
+
+
+    /**
+     * XML格式字符串转换为Map
+     *
+     * @param strXML XML字符串
+     * @return XML数据转换后的Map
+     * @throws Exception
+     */
+    public static Map<String, String> xmlToMap(String strXML) throws Exception {
+        log.info("4....");
+        try {
+            Map<String, String> data = new HashMap<>();
+            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+            InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
+            org.w3c.dom.Document doc = documentBuilder.parse(stream);
+            doc.getDocumentElement().normalize();
+            NodeList nodeList = doc.getDocumentElement().getChildNodes();
+            for (int idx = 0; idx < nodeList.getLength(); ++idx) {
+                Node node = nodeList.item(idx);
+                if (node.getNodeType() == Node.ELEMENT_NODE) {
+                    org.w3c.dom.Element element = (org.w3c.dom.Element) node;
+                    data.put(element.getNodeName(), element.getTextContent());
+                }
+            }
+            try {
+                stream.close();
+            } catch (Exception ex) {
+                // do nothing
+            }
+            return data;
+        } catch (Exception ex) {
+            throw ex;
+        }
+    }
+
+    /**
+     * 将Map转换为XML格式的字符串
+     *
+     * @param data Map类型数据
+     * @return XML格式的字符串
+     * @throws Exception
+     */
+    public static String mapToXml(Map<String, String> data) throws Exception {
+        log.info("----mapToXml-----"+data);
+        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
+        org.w3c.dom.Document document = documentBuilder.newDocument();
+        org.w3c.dom.Element root = document.createElement("xml");
+        document.appendChild(root);
+        for (String key: data.keySet()) {
+            String value = data.get(key);
+            if (value == null) {
+                value = "";
+            }
+            value = value.trim();
+            org.w3c.dom.Element filed = document.createElement(key);
+            filed.appendChild(document.createTextNode(value));
+            root.appendChild(filed);
+        }
+        TransformerFactory tf = TransformerFactory.newInstance();
+        Transformer transformer = tf.newTransformer();
+        DOMSource source = new DOMSource(document);
+        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+        StringWriter writer = new StringWriter();
+        StreamResult result = new StreamResult(writer);
+        transformer.transform(source, result);
+        String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
+        try {
+            writer.close();
+        } catch (Exception ex) {
+
+        }
+        log.info("----mapToXml-return-----"+output);
+        return output;
+    }
+
+
+
+
+
+
+}

+ 5 - 4
twzd-admin/src/main/resources/application-dev.yml

@@ -57,13 +57,12 @@ spring:
                         multi-statement-allow: true
     # redis 配置
     redis:
-        database: 2
         # 地址
-        host: 192.168.8.213
+        host: 1.15.29.64
         # 端口,默认为6379
         port: 6379
         # 密码
-        password:
+        password: miaxis110
         # 连接超时时间
         timeout: 10s
         lettuce:
@@ -76,10 +75,12 @@ spring:
                 max-active: 8
                 # #连接池最大阻塞等待时间(使用负值表示没有限制)
                 max-wait: -1ms
+        # 指定库
+        database: 12
 
 
 
-
+# 微信公众号
 app:
     appId: wx67ca1b8c9816ef28
     appSecret: 8604f2a6eb6338cfa64e7df4ec2c08b3

+ 4 - 1
twzd-admin/src/main/resources/application-prod.yml

@@ -64,7 +64,7 @@ spring:
         # 密码
         password: miaxis110
         # 连接超时时间
-        timeout: 10s
+        timeout: 10000
         lettuce:
             pool:
                 # 连接池中的最小空闲连接
@@ -75,7 +75,10 @@ spring:
                 max-active: 8
                 # #连接池最大阻塞等待时间(使用负值表示没有限制)
                 max-wait: -1ms
+        # 指定库
+        database: 12
 
+# 微信公众号
 app:
     appId: wx67ca1b8c9816ef28
     appSecret: 8604f2a6eb6338cfa64e7df4ec2c08b3

+ 74 - 0
twzd-common/src/main/java/com/miaxis/common/utils/wx/SignUtil.java

@@ -0,0 +1,74 @@
+package com.miaxis.common.utils.wx;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+/**
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/21 16:20
+ */
+public class SignUtil {
+
+    private static String token = "twzd";// 与微信公众号上的token一致,是服务器令牌(token),这里写什么。服务器就填什么
+
+    /**
+     * 校验签名
+     *
+     * @param signature 签名
+     * @param timestamp 时间戳
+     * @param nonce     随机数
+     * @return 布尔值
+     */
+    public static boolean checkSignature(String signature, String timestamp, String nonce) {
+        String checktext = null;
+        if (null != signature) {
+            //对ToKen,timestamp,nonce 按字典排序
+            String[] paramArr = new String[]{token, timestamp, nonce};
+            Arrays.sort(paramArr);
+            //将排序后的结果拼成一个字符串
+            String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]);
+            try {
+                MessageDigest md = MessageDigest.getInstance("SHA-1");
+                //对接后的字符串进行sha1加密
+                byte[] digest = md.digest(content.toString().getBytes());
+                checktext = byteToStr(digest);
+            } catch (NoSuchAlgorithmException e) {
+                e.printStackTrace();
+            }
+        }
+        //将加密后的字符串与signature进行对比
+        return checktext != null ? checktext.equals(signature.toUpperCase()) : false;
+    }
+
+    /**
+     * 将字节数组转化我16进制字符串
+     *
+     * @param byteArrays 字符数组
+     * @return 字符串
+     */
+    private static String byteToStr(byte[] byteArrays) {
+        String str = "";
+        for (int i = 0; i < byteArrays.length; i++) {
+            str += byteToHexStr(byteArrays[i]);
+        }
+        return str;
+    }
+
+    /**
+     * 将字节转化为十六进制字符串
+     *
+     * @param myByte 字节
+     * @return 字符串
+     */
+    private static String byteToHexStr(byte myByte) {
+        char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+        char[] tampArr = new char[2];
+        tampArr[0] = Digit[(myByte >>> 4) & 0X0F];
+        tampArr[1] = Digit[myByte & 0X0F];
+        String str = new String(tampArr);
+        return str;
+    }
+
+}

+ 22 - 0
twzd-service/src/main/java/com/miaxis/feign/dto/WxTicket.java

@@ -0,0 +1,22 @@
+package com.miaxis.feign.dto;
+
+import lombok.Data;
+
+/**
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/20 15:08
+ */
+@Data
+public class WxTicket {
+
+    private Integer expire_seconds;  //该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为60秒。
+    private String action_name;  //二维码类型,QR_SCENE为临时的整型参数值,QR_STR_SCENE为临时的字符串参数值,QR_LIMIT_SCENE为永久的整型参数值,QR_LIMIT_STR_SCENE为永久的字符串参数值
+
+    /**
+     * 二维码详细信息
+     *      参数:scene_id:场景值ID,临时二维码时为32位非0整型,永久二维码时最大值为100000(目前参数只支持1--100000)
+     *            scene_str:场景值ID(字符串形式的ID),字符串类型,长度限制为1到64
+     */
+    private Object action_info;  //二维码详细信息
+}

+ 36 - 0
twzd-service/src/main/java/com/miaxis/feign/service/IWxMpService.java

@@ -0,0 +1,36 @@
+package com.miaxis.feign.service;
+
+import com.miaxis.common.config.FeignConfig;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import javax.servlet.annotation.HandlesTypes;
+
+/**
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/20 16:05
+ */
+@FeignClient(name="wxMpService",
+        url = "https://mp.weixin.qq.com/cgi-bin",configuration = FeignConfig.class)
+public interface IWxMpService {
+
+    /**
+     * 通过ticket换取二维码
+     * HTTP头(示例)如下:
+     *      Accept-Ranges:bytes
+     *      Cache-control:max-age=604800
+     *      Connection:keep-alive
+     *      Content-Length:28026
+     *      Content-Type:image/jpg
+     *      Date:Wed, 16 Oct 2013 06:37:10 GMT
+     *      Expires:Wed, 23 Oct 2013 14:37:10 +0800
+     *      Server:nginx/1.4.1
+     * @param ticket
+     * @return
+     */
+    @GetMapping(value = "/showqrcode"
+            ,headers = {"Accept-Ranges=bytes", "Cache-control='max-age=604800'", "Connection=keep-alive","Content-Length=28026","Content-Type=image/jpg"})
+    String showQrcode(@RequestParam("ticket") String ticket);
+}

+ 45 - 0
twzd-service/src/main/java/com/miaxis/feign/service/IWxSendService.java

@@ -0,0 +1,45 @@
+package com.miaxis.feign.service;
+
+import com.miaxis.common.config.FeignConfig;
+import com.miaxis.feign.dto.WxTicket;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+/**
+ * 微信公众号接口
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/20 14:59
+ */
+@FeignClient(name="wxSendService",
+        url = "https://api.weixin.qq.com/cgi-bin",configuration = FeignConfig.class)
+public interface IWxSendService {
+
+
+    /**
+     *  获取token
+     * @param grant_type
+     * @param appid 第三方用户唯一凭证
+     * @param secret 第三方用户唯一凭证密钥,即appsecret
+     * @return
+     */
+    @GetMapping(value = "/token")
+    String getAccessToken(@RequestParam("grant_type") String grant_type,
+                          @RequestParam("appid") String appid,
+                          @RequestParam("secret") String secret);
+
+
+    /**
+     * 生成带参数二维码接口
+     *      -文档链接:https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html
+     * @param accessToken
+     * @param wxTicket:二维码参数
+     * @return
+     */
+    @PostMapping(value = "/qrcode/create")
+    String generateTicket(@RequestParam("access_token")String accessToken, WxTicket wxTicket);
+
+
+}

+ 522 - 0
twzd-service/src/main/java/com/miaxis/qustion/domain/QuestionInfo.java

@@ -0,0 +1,522 @@
+package com.miaxis.qustion.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.miaxis.common.annotation.Excel;
+import com.miaxis.common.core.domain.BaseBusinessEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+/**
+ * 题库对象 question_info
+ *
+ * @author miaxis
+ * @date 2021-10-20
+ */
+@Data
+@TableName("question_info")
+@ApiModel(value = "QuestionInfo", description = "题库对象 question_info")
+public class QuestionInfo extends BaseBusinessEntity{
+    private static final long serialVersionUID = 1L;
+
+    /**  主键 */
+    @TableId(value = "id")
+    @ApiModelProperty(value = " 主键")
+    private Long id;
+
+    /** 在所有题目中的序号 */
+    @Excel(name = "在所有题目中的序号")
+    @TableField("number")
+    @ApiModelProperty(value = "在所有题目中的序号")
+    private Long number;
+
+    /** 正确答案 */
+    @Excel(name = "正确答案")
+    @TableField("answer")
+    @ApiModelProperty(value = "正确答案")
+    private String answer;
+
+    /** 答案关键词 */
+    @Excel(name = "答案关键词")
+    @TableField("answerkeyword")
+    @ApiModelProperty(value = "答案关键词")
+    private String answerkeyword;
+
+    /** 技巧讲解图片URL */
+    @Excel(name = "技巧讲解图片URL")
+    @TableField("explain_gif")
+    @ApiModelProperty(value = "技巧讲解图片URL")
+    private String explainGif;
+
+    /** 技巧讲解说明 */
+    @Excel(name = "技巧讲解说明")
+    @TableField("explain_jq")
+    @ApiModelProperty(value = "技巧讲解说明")
+    private String explainJq;
+
+    /** 官方解释 */
+    @Excel(name = "官方解释")
+    @TableField("explain_js")
+    @ApiModelProperty(value = "官方解释")
+    private String explainJs;
+
+    /** 技巧讲解语音URL */
+    @Excel(name = "技巧讲解语音URL")
+    @TableField("explain_mp3")
+    @ApiModelProperty(value = "技巧讲解语音URL")
+    private String explainMp3;
+
+    /** 题目图片URL */
+    @Excel(name = "题目图片URL")
+    @TableField("image")
+    @ApiModelProperty(value = "题目图片URL")
+    private String image;
+
+    /** 题目图片URL2 */
+    @Excel(name = "题目图片URL2")
+    @TableField("image_ydt")
+    @ApiModelProperty(value = "题目图片URL2")
+    private String imageYdt;
+
+    /** 题目 */
+    @Excel(name = "题目")
+    @TableField("issue")
+    @ApiModelProperty(value = "题目")
+    private String issue;
+
+    /** 答案选项 */
+    @Excel(name = "答案选项")
+    @TableField("opts")
+    @ApiModelProperty(value = "答案选项")
+    private String opts;
+
+    /** 答题技巧关键词 */
+    @Excel(name = "答题技巧关键词")
+    @TableField("skillkeyword")
+    @ApiModelProperty(value = "答题技巧关键词")
+    private String skillkeyword;
+
+    /** 题目关键词 */
+    @Excel(name = "题目关键词")
+    @TableField("titlekeyword")
+    @ApiModelProperty(value = "题目关键词")
+    private String titlekeyword;
+
+    /** 读题语音URL */
+    @Excel(name = "读题语音URL")
+    @TableField("issuemp3")
+    @ApiModelProperty(value = "读题语音URL")
+    private String issuemp3;
+
+    /** 答案语音URL */
+    @Excel(name = "答案语音URL")
+    @TableField("answermp3")
+    @ApiModelProperty(value = "答案语音URL")
+    private String answermp3;
+
+    /** 读题+答案语音URL */
+    @Excel(name = "读题+答案语音URL")
+    @TableField("explainjsmp3")
+    @ApiModelProperty(value = "读题+答案语音URL")
+    private String explainjsmp3;
+
+    /** 是否是科目一题目 */
+    @Excel(name = "是否是科目一题目")
+    @TableField("subject_1")
+    @ApiModelProperty(value = "是否是科目一题目")
+    private String subject1;
+
+    /** 是否是科目二题目 */
+    @Excel(name = "是否是科目二题目")
+    @TableField("subject_2")
+    @ApiModelProperty(value = "是否是科目二题目")
+    private String subject2;
+
+    /** 是否是科目三题目 */
+    @Excel(name = "是否是科目三题目")
+    @TableField("subject_3")
+    @ApiModelProperty(value = "是否是科目三题目")
+    private String subject3;
+
+    /** 是否是科目四题目 */
+    @Excel(name = "是否是科目四题目")
+    @TableField("subject_4")
+    @ApiModelProperty(value = "是否是科目四题目")
+    private String subject4;
+
+    /** 是否是C1,C2,C3驾驶证题目 */
+    @Excel(name = "是否是C1,C2,C3驾驶证题目")
+    @TableField("lice_car")
+    @ApiModelProperty(value = "是否是C1,C2,C3驾驶证题目")
+    private String liceCar;
+
+    /** 是否是A1\A3\B1驾驶证题目 */
+    @Excel(name = "是否是A1,A3,B1驾驶证题目")
+    @TableField("lice_bus")
+    @ApiModelProperty(value = "是否是A1,A3,B1驾驶证题目")
+    private String liceBus;
+
+    /** 是否是A2\B2驾驶证题目 */
+    @Excel(name = "是否是A2,B2驾驶证题目")
+    @TableField("lice_truck")
+    @ApiModelProperty(value = "是否是A2,B2驾驶证题目")
+    private String liceTruck;
+
+    /** 是否是D\E\F驾驶证题目 */
+    @Excel(name = "是否是D,E,F驾驶证题目")
+    @TableField("lice_moto")
+    @ApiModelProperty(value = "是否是D,E,F驾驶证题目")
+    private String liceMoto;
+
+    /** 顺序练习分类(包含科一到科四) */
+    @Excel(name = "顺序练习分类(包含科一到科四)", readConverterExp = "包=含科一到科四")
+    @TableField("seque_issue")
+    @ApiModelProperty(value = "顺序练习分类(包含科一到科四)")
+    private String sequeIssue;
+
+    /** 分类练习(包含科一到科四) */
+    @Excel(name = "分类练习(包含科一到科四)", readConverterExp = "包=含科一到科四")
+    @TableField("class_issue")
+    @ApiModelProperty(value = "分类练习(包含科一到科四)")
+    private String classIssue;
+
+    /** 地方专题(包含科一到科四) */
+    @Excel(name = "地方专题(包含科一到科四)", readConverterExp = "包=含科一到科四")
+    @TableField("place_issue")
+    @ApiModelProperty(value = "地方专题(包含科一到科四)")
+    private String placeIssue;
+
+    /** 精选题(包含科一到科四) */
+    @Excel(name = "精选题(包含科一到科四)", readConverterExp = "包=含科一到科四")
+    @TableField("excell_issue")
+    @ApiModelProperty(value = "精选题(包含科一到科四)")
+    private String excellIssue;
+
+    /** 是否是仿真考试题目 */
+    @Excel(name = "是否是仿真考试题目")
+    @TableField("copy_issue")
+    @ApiModelProperty(value = "是否是仿真考试题目")
+    private String copyIssue;
+
+    /** 是否是真实考场模拟题目 */
+    @Excel(name = "是否是真实考场模拟题目")
+    @TableField("mock_issue")
+    @ApiModelProperty(value = "是否是真实考场模拟题目")
+    private String mockIssue;
+
+    /** 题目在顺序练习中所属的模块名称 */
+    @Excel(name = "题目在顺序练习中所属的模块名称")
+    @TableField("seque_issue_name")
+    @ApiModelProperty(value = "题目在顺序练习中所属的模块名称")
+    private String sequeIssueName;
+
+    /** 题目在地方专题中所属的模块名称 */
+    @Excel(name = "题目在地方专题中所属的模块名称")
+    @TableField("place_issue_name")
+    @ApiModelProperty(value = "题目在地方专题中所属的模块名称")
+    private String placeIssueName;
+
+    /** 题目在精选中所属的模块名称 */
+    @Excel(name = "题目在精选中所属的模块名称")
+    @TableField("excell_issue_name")
+    @ApiModelProperty(value = "题目在精选中所属的模块名称")
+    private String excellIssueName;
+
+    /** 题目在分类中所属的模块名称 */
+    @Excel(name = "题目在分类中所属的模块名称")
+    @TableField("class_issue_name")
+    @ApiModelProperty(value = "题目在分类中所属的模块名称")
+    private String classIssueName;
+
+    public void setId(Long id){
+        this.id = id;
+    }
+
+    public Long getId(){
+        return id;
+    }
+    public void setNumber(Long number){
+        this.number = number;
+    }
+
+    public Long getNumber(){
+        return number;
+    }
+    public void setAnswer(String answer){
+        this.answer = answer;
+    }
+
+    public String getAnswer(){
+        return answer;
+    }
+    public void setAnswerkeyword(String answerkeyword){
+        this.answerkeyword = answerkeyword;
+    }
+
+    public String getAnswerkeyword(){
+        return answerkeyword;
+    }
+    public void setExplainGif(String explainGif){
+        this.explainGif = explainGif;
+    }
+
+    public String getExplainGif(){
+        return explainGif;
+    }
+    public void setExplainJq(String explainJq){
+        this.explainJq = explainJq;
+    }
+
+    public String getExplainJq(){
+        return explainJq;
+    }
+    public void setExplainJs(String explainJs){
+        this.explainJs = explainJs;
+    }
+
+    public String getExplainJs(){
+        return explainJs;
+    }
+    public void setExplainMp3(String explainMp3){
+        this.explainMp3 = explainMp3;
+    }
+
+    public String getExplainMp3(){
+        return explainMp3;
+    }
+    public void setImage(String image){
+        this.image = image;
+    }
+
+    public String getImage(){
+        return image;
+    }
+    public void setImageYdt(String imageYdt){
+        this.imageYdt = imageYdt;
+    }
+
+    public String getImageYdt(){
+        return imageYdt;
+    }
+    public void setIssue(String issue){
+        this.issue = issue;
+    }
+
+    public String getIssue(){
+        return issue;
+    }
+    public void setOpts(String opts){
+        this.opts = opts;
+    }
+
+    public String getOpts(){
+        return opts;
+    }
+    public void setSkillkeyword(String skillkeyword){
+        this.skillkeyword = skillkeyword;
+    }
+
+    public String getSkillkeyword(){
+        return skillkeyword;
+    }
+    public void setTitlekeyword(String titlekeyword){
+        this.titlekeyword = titlekeyword;
+    }
+
+    public String getTitlekeyword(){
+        return titlekeyword;
+    }
+    public void setIssuemp3(String issuemp3){
+        this.issuemp3 = issuemp3;
+    }
+
+    public String getIssuemp3(){
+        return issuemp3;
+    }
+    public void setAnswermp3(String answermp3){
+        this.answermp3 = answermp3;
+    }
+
+    public String getAnswermp3(){
+        return answermp3;
+    }
+    public void setExplainjsmp3(String explainjsmp3){
+        this.explainjsmp3 = explainjsmp3;
+    }
+
+    public String getExplainjsmp3(){
+        return explainjsmp3;
+    }
+    public void setSubject1(String subject1){
+        this.subject1 = subject1;
+    }
+
+    public String getSubject1(){
+        return subject1;
+    }
+    public void setSubject2(String subject2){
+        this.subject2 = subject2;
+    }
+
+    public String getSubject2(){
+        return subject2;
+    }
+    public void setSubject3(String subject3){
+        this.subject3 = subject3;
+    }
+
+    public String getSubject3(){
+        return subject3;
+    }
+    public void setSubject4(String subject4){
+        this.subject4 = subject4;
+    }
+
+    public String getSubject4(){
+        return subject4;
+    }
+    public void setLiceCar(String liceCar){
+        this.liceCar = liceCar;
+    }
+
+    public String getLiceCar(){
+        return liceCar;
+    }
+    public void setLiceBus(String liceBus){
+        this.liceBus = liceBus;
+    }
+
+    public String getLiceBus(){
+        return liceBus;
+    }
+    public void setLiceTruck(String liceTruck){
+        this.liceTruck = liceTruck;
+    }
+
+    public String getLiceTruck(){
+        return liceTruck;
+    }
+    public void setLiceMoto(String liceMoto){
+        this.liceMoto = liceMoto;
+    }
+
+    public String getLiceMoto(){
+        return liceMoto;
+    }
+    public void setSequeIssue(String sequeIssue){
+        this.sequeIssue = sequeIssue;
+    }
+
+    public String getSequeIssue(){
+        return sequeIssue;
+    }
+    public void setClassIssue(String classIssue){
+        this.classIssue = classIssue;
+    }
+
+    public String getClassIssue(){
+        return classIssue;
+    }
+    public void setPlaceIssue(String placeIssue){
+        this.placeIssue = placeIssue;
+    }
+
+    public String getPlaceIssue(){
+        return placeIssue;
+    }
+    public void setExcellIssue(String excellIssue){
+        this.excellIssue = excellIssue;
+    }
+
+    public String getExcellIssue(){
+        return excellIssue;
+    }
+    public void setCopyIssue(String copyIssue){
+        this.copyIssue = copyIssue;
+    }
+
+    public String getCopyIssue(){
+        return copyIssue;
+    }
+    public void setMockIssue(String mockIssue){
+        this.mockIssue = mockIssue;
+    }
+
+    public String getMockIssue(){
+        return mockIssue;
+    }
+    public void setSequeIssueName(String sequeIssueName){
+        this.sequeIssueName = sequeIssueName;
+    }
+
+    public String getSequeIssueName(){
+        return sequeIssueName;
+    }
+    public void setPlaceIssueName(String placeIssueName){
+        this.placeIssueName = placeIssueName;
+    }
+
+    public String getPlaceIssueName(){
+        return placeIssueName;
+    }
+    public void setExcellIssueName(String excellIssueName){
+        this.excellIssueName = excellIssueName;
+    }
+
+    public String getExcellIssueName(){
+        return excellIssueName;
+    }
+    public void setClassIssueName(String classIssueName){
+        this.classIssueName = classIssueName;
+    }
+
+    public String getClassIssueName(){
+        return classIssueName;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("number", getNumber())
+            .append("answer", getAnswer())
+            .append("answerkeyword", getAnswerkeyword())
+            .append("explainGif", getExplainGif())
+            .append("explainJq", getExplainJq())
+            .append("explainJs", getExplainJs())
+            .append("explainMp3", getExplainMp3())
+            .append("image", getImage())
+            .append("imageYdt", getImageYdt())
+            .append("issue", getIssue())
+            .append("opts", getOpts())
+            .append("skillkeyword", getSkillkeyword())
+            .append("titlekeyword", getTitlekeyword())
+            .append("issuemp3", getIssuemp3())
+            .append("answermp3", getAnswermp3())
+            .append("explainjsmp3", getExplainjsmp3())
+            .append("subject1", getSubject1())
+            .append("subject2", getSubject2())
+            .append("subject3", getSubject3())
+            .append("subject4", getSubject4())
+            .append("liceCar", getLiceCar())
+            .append("liceBus", getLiceBus())
+            .append("liceTruck", getLiceTruck())
+            .append("liceMoto", getLiceMoto())
+            .append("sequeIssue", getSequeIssue())
+            .append("classIssue", getClassIssue())
+            .append("placeIssue", getPlaceIssue())
+            .append("excellIssue", getExcellIssue())
+            .append("copyIssue", getCopyIssue())
+            .append("mockIssue", getMockIssue())
+            .append("sequeIssueName", getSequeIssueName())
+            .append("placeIssueName", getPlaceIssueName())
+            .append("excellIssueName", getExcellIssueName())
+            .append("classIssueName", getClassIssueName())
+            .append("createTime", getCreateTime())
+            .append("updateTime", getUpdateTime())
+            .toString();
+    }
+}

+ 22 - 0
twzd-service/src/main/java/com/miaxis/qustion/mapper/QuestionInfoMapper.java

@@ -0,0 +1,22 @@
+package com.miaxis.qustion.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.miaxis.qustion.domain.QuestionInfo;
+
+/**
+ * 题库Mapper接口
+ *
+ * @author miaxis
+ * @date 2021-10-20
+ */
+public interface QuestionInfoMapper extends BaseMapper<QuestionInfo> {
+    /**
+     * 查询题库列表
+     *
+     * @param questionInfo 题库
+     * @return 题库集合
+     */
+    public List<QuestionInfo> selectQuestionInfoList(QuestionInfo questionInfo);
+
+}

+ 21 - 0
twzd-service/src/main/java/com/miaxis/qustion/service/IQuestionInfoService.java

@@ -0,0 +1,21 @@
+package com.miaxis.qustion.service;
+
+import java.util.List;
+import com.miaxis.qustion.domain.QuestionInfo;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * 题库Service接口
+ *
+ * @author miaxis
+ * @date 2021-10-20
+ */
+public interface IQuestionInfoService extends IService<QuestionInfo>{
+    /**
+     * 查询题库列表
+     *
+     * @param questionInfo 题库
+     * @return 题库集合
+     */
+    public List<QuestionInfo> selectQuestionInfoList(QuestionInfo questionInfo);
+}

+ 36 - 0
twzd-service/src/main/java/com/miaxis/qustion/service/impl/QuestionInfoServiceImpl.java

@@ -0,0 +1,36 @@
+package com.miaxis.qustion.service.impl;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.miaxis.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.apache.commons.lang3.StringUtils;
+import com.miaxis.qustion.mapper.QuestionInfoMapper;
+import com.miaxis.qustion.domain.QuestionInfo;
+import com.miaxis.qustion.service.IQuestionInfoService;
+
+/**
+ * 题库Service业务层处理
+ *
+ * @author miaxis
+ * @date 2021-10-20
+ */
+@Service
+public class QuestionInfoServiceImpl extends ServiceImpl<QuestionInfoMapper, QuestionInfo> implements IQuestionInfoService {
+    @Autowired
+    private QuestionInfoMapper questionInfoMapper;
+
+    /**
+     * 查询题库列表
+     *
+     * @param questionInfo 题库
+     * @return 题库
+     */
+    @Override
+    public List<QuestionInfo> selectQuestionInfoList(QuestionInfo questionInfo){
+        return questionInfoMapper.selectQuestionInfoList(questionInfo);
+    }
+}

+ 15 - 0
twzd-service/src/main/java/com/miaxis/wx/service/IWxGzhService.java

@@ -0,0 +1,15 @@
+package com.miaxis.wx.service;
+
+/**
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/20 14:56
+ */
+public interface IWxGzhService {
+
+    /**
+     * 获取微信公众号token
+     * @return
+     */
+    String getGzhToken();
+}

+ 61 - 0
twzd-service/src/main/java/com/miaxis/wx/service/impl/WxGzhServiceImpl.java

@@ -0,0 +1,61 @@
+package com.miaxis.wx.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.miaxis.common.constant.Constants;
+import com.miaxis.common.core.redis.RedisCache;
+import com.miaxis.common.utils.StringUtils;
+import com.miaxis.feign.service.IWxSendService;
+import com.miaxis.wx.service.IWxGzhService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 微信公众号业务层
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/20 14:57
+ */
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class WxGzhServiceImpl implements IWxGzhService {
+
+    private final RedisTemplate redisTemplate;
+
+    private final  IWxSendService wxSendService;
+
+    @Value("${app.appid}")
+    private String appid;
+
+    @Value("${app.appSecret}")
+    private String secret;
+
+
+    @Override
+    public String getGzhToken() {
+        String token = "";
+        Integer expiresIn;
+        if (redisTemplate.hasKey(Constants.GZH_MESSAGE_TOKEN)){
+            token = (String)redisTemplate.opsForValue().get(Constants.GZH_MESSAGE_TOKEN);
+        }
+        if (StringUtils.isEmpty(token)){
+            String result = wxSendService.getAccessToken("client_credential",appid,secret);
+            JSONObject json = JSONObject.parseObject(result);
+            token = json.getString("access_token");
+            expiresIn = json.getIntValue("expires_in");
+            if (expiresIn <= 0){
+                expiresIn = 7000;
+            }
+
+            redisTemplate.opsForValue().set(Constants.GZH_MESSAGE_TOKEN,token,expiresIn, TimeUnit.SECONDS);
+        }
+
+        return token;
+    }
+}

+ 94 - 0
twzd-service/src/main/resources/mapper/qustion/QuestionInfoMapper.xml

@@ -0,0 +1,94 @@
+<?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.miaxis.qustion.mapper.QuestionInfoMapper">
+
+    <resultMap type="QuestionInfo" id="QuestionInfoResult">
+        <result property="id"    column="id"    />
+        <result property="number"    column="number"    />
+        <result property="answer"    column="answer"    />
+        <result property="answerkeyword"    column="answerkeyword"    />
+        <result property="explainGif"    column="explain_gif"    />
+        <result property="explainJq"    column="explain_jq"    />
+        <result property="explainJs"    column="explain_js"    />
+        <result property="explainMp3"    column="explain_mp3"    />
+        <result property="image"    column="image"    />
+        <result property="imageYdt"    column="image_ydt"    />
+        <result property="issue"    column="issue"    />
+        <result property="opts"    column="opts"    />
+        <result property="skillkeyword"    column="skillkeyword"    />
+        <result property="titlekeyword"    column="titlekeyword"    />
+        <result property="issuemp3"    column="issuemp3"    />
+        <result property="answermp3"    column="answermp3"    />
+        <result property="explainjsmp3"    column="explainjsmp3"    />
+        <result property="subject1"    column="subject_1"    />
+        <result property="subject2"    column="subject_2"    />
+        <result property="subject3"    column="subject_3"    />
+        <result property="subject4"    column="subject_4"    />
+        <result property="liceCar"    column="lice_car"    />
+        <result property="liceBus"    column="lice_bus"    />
+        <result property="liceTruck"    column="lice_truck"    />
+        <result property="liceMoto"    column="lice_moto"    />
+        <result property="sequeIssue"    column="seque_issue"    />
+        <result property="classIssue"    column="class_issue"    />
+        <result property="placeIssue"    column="place_issue"    />
+        <result property="excellIssue"    column="excell_issue"    />
+        <result property="copyIssue"    column="copy_issue"    />
+        <result property="mockIssue"    column="mock_issue"    />
+        <result property="sequeIssueName"    column="seque_issue_name"    />
+        <result property="placeIssueName"    column="place_issue_name"    />
+        <result property="excellIssueName"    column="excell_issue_name"    />
+        <result property="classIssueName"    column="class_issue_name"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+
+    <sql id="selectQuestionInfoVo">
+        select * from question_info
+    </sql>
+
+    <select id="selectQuestionInfoList" parameterType="QuestionInfo" resultMap="QuestionInfoResult">
+        <include refid="selectQuestionInfoVo"/>
+        <where>
+            <if test="number != null "> and number = #{number}</if>
+            <if test="answer != null  and answer != ''"> and answer = #{answer}</if>
+            <if test="answerkeyword != null  and answerkeyword != ''"> and answerkeyword = #{answerkeyword}</if>
+            <if test="explainGif != null  and explainGif != ''"> and explain_gif = #{explainGif}</if>
+            <if test="explainJq != null  and explainJq != ''"> and explain_jq = #{explainJq}</if>
+            <if test="explainJs != null  and explainJs != ''"> and explain_js = #{explainJs}</if>
+            <if test="explainMp3 != null  and explainMp3 != ''"> and explain_mp3 = #{explainMp3}</if>
+            <if test="image != null  and image != ''"> and image = #{image}</if>
+            <if test="imageYdt != null  and imageYdt != ''"> and image_ydt = #{imageYdt}</if>
+            <if test="issue != null  and issue != ''"> and issue = #{issue}</if>
+            <if test="opts != null  and opts != ''"> and opts = #{opts}</if>
+            <if test="skillkeyword != null  and skillkeyword != ''"> and skillkeyword = #{skillkeyword}</if>
+            <if test="titlekeyword != null  and titlekeyword != ''"> and titlekeyword = #{titlekeyword}</if>
+            <if test="issuemp3 != null  and issuemp3 != ''"> and issuemp3 = #{issuemp3}</if>
+            <if test="answermp3 != null  and answermp3 != ''"> and answermp3 = #{answermp3}</if>
+            <if test="explainjsmp3 != null  and explainjsmp3 != ''"> and explainjsmp3 = #{explainjsmp3}</if>
+            <if test="subject1 != null  and subject1 != ''"> and subject_1 = #{subject1}</if>
+            <if test="subject2 != null  and subject2 != ''"> and subject_2 = #{subject2}</if>
+            <if test="subject3 != null  and subject3 != ''"> and subject_3 = #{subject3}</if>
+            <if test="subject4 != null  and subject4 != ''"> and subject_4 = #{subject4}</if>
+            <if test="liceCar != null  and liceCar != ''"> and lice_car = #{liceCar}</if>
+            <if test="liceBus != null  and liceBus != ''"> and lice_bus = #{liceBus}</if>
+            <if test="liceTruck != null  and liceTruck != ''"> and lice_truck = #{liceTruck}</if>
+            <if test="liceMoto != null  and liceMoto != ''"> and lice_moto = #{liceMoto}</if>
+            <if test="sequeIssue != null  and sequeIssue != ''"> and seque_issue = #{sequeIssue}</if>
+            <if test="classIssue != null  and classIssue != ''"> and class_issue = #{classIssue}</if>
+            <if test="placeIssue != null  and placeIssue != ''"> and place_issue = #{placeIssue}</if>
+            <if test="excellIssue != null  and excellIssue != ''"> and excell_issue = #{excellIssue}</if>
+            <if test="copyIssue != null  and copyIssue != ''"> and copy_issue = #{copyIssue}</if>
+            <if test="mockIssue != null  and mockIssue != ''"> and mock_issue = #{mockIssue}</if>
+            <if test="sequeIssueName != null  and sequeIssueName != ''"> and seque_issue_name like concat('%', #{sequeIssueName}, '%')</if>
+            <if test="placeIssueName != null  and placeIssueName != ''"> and place_issue_name like concat('%', #{placeIssueName}, '%')</if>
+            <if test="excellIssueName != null  and excellIssueName != ''"> and excell_issue_name like concat('%', #{excellIssueName}, '%')</if>
+            <if test="classIssueName != null  and classIssueName != ''"> and class_issue_name like concat('%', #{classIssueName}, '%')</if>
+        </where>
+    </select>
+
+
+
+
+</mapper>