瀏覽代碼

Merge remote-tracking branch 'origin/master'

yanliming 5 年之前
父節點
當前提交
c18ef9daeb

+ 99 - 5
picc-enterprise-server/src/main/java/com/jpsoft/picc/modules/auth/controller/AttachmentController.java

@@ -1,6 +1,12 @@
 package com.jpsoft.picc.modules.auth.controller;
 
-import com.alibaba.druid.util.StringUtils;
+import com.jpsoft.picc.config.CasConfig;
+import com.jpsoft.picc.modules.base.entity.Company;
+import com.jpsoft.picc.modules.base.entity.CompanyMember;
+import com.jpsoft.picc.modules.base.service.CompanyMemberService;
+import com.jpsoft.picc.modules.base.service.CompanyService;
+import com.jpsoft.picc.modules.business.entity.InsurancePolicyMember;
+import com.jpsoft.picc.modules.business.service.InsurancePolicyMemberService;
 import com.jpsoft.picc.modules.common.config.OSSConfig;
 import com.jpsoft.picc.modules.common.dto.MessageResult;
 import com.jpsoft.picc.modules.common.utils.OSSUtil;
@@ -9,22 +15,46 @@ import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.jasig.cas.client.authentication.AttributePrincipal;
+import org.omg.CORBA.Environment;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 @Api(description="附件管理")
-@RestController
+@Controller
 @RequestMapping("/auth/attachment")
 @Slf4j
 public class AttachmentController {
     @Autowired
     private OSSConfig ossConfig;
 
+    @Autowired
+    private CasConfig casConfig;
+
+    @Autowired
+    private CompanyService companyService;
+
+    @Autowired
+    private InsurancePolicyMemberService insurancePolicyMemberService;
+
+    @Autowired
+    private CompanyMemberService companyMemberService;
+
     @PostMapping("upload")
     @ApiOperation(value="附件上传")
+    @ResponseBody
     @ApiImplicitParams({
             @ApiImplicitParam(name = "fileName",value = "文件名", required = false, paramType = "form"),
             @ApiImplicitParam(name = "subFolder",value = "子目录名(如/test)", required = false, paramType = "form"),
@@ -52,4 +82,68 @@ public class AttachmentController {
 
         return messageResult;
     }
+
+    @ApiOperation(value="身份证附件打包下载")
+    @RequestMapping(value = "downloadIdCardZip",method = RequestMethod.GET)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name="policyId",value = "每月投保单ID",required = true,paramType = "query")
+    })
+    public void downloadIdCardZip(String policyId, HttpServletRequest request,HttpServletResponse response){
+        try {
+            Long lastDownloadIdCardTime = (Long)request.getSession().getAttribute("lastDownloadIdCardTime");
+
+            response.setCharacterEncoding("utf-8");
+
+            if (lastDownloadIdCardTime!=null && (System.currentTimeMillis() - lastDownloadIdCardTime)<5000){
+                response.setContentType("text/html; charset=UTF-8");
+                response.getWriter().println("下载过于频繁,请稍后再试!");
+                return;
+            }
+
+            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
+
+            //设置编码  为了解决中文名称乱码问题
+            String fileName = "身份证";
+            String zipFileName = new String(fileName.getBytes("UTF-8"), "iso-8859-1");
+            response.setHeader("Content-Disposition", "attachment;fileName=" + zipFileName + ".zip");
+
+            List<InsurancePolicyMember> policyMemberList = insurancePolicyMemberService.findByPolicyId(policyId);
+
+            List<Map<String,String>> fileList = new ArrayList<>();
+
+            for (InsurancePolicyMember policyMember : policyMemberList) {
+                CompanyMember member = companyMemberService.get(policyMember.getMemberId());
+
+                String urls = member.getCardFiles();
+
+                if (StringUtils.isNotEmpty(urls)){
+                    String[] arr = urls.split("\\|");
+
+                    for(int i=0;i<arr.length;i++) {
+                        String url = arr[i];
+
+                        String ext = url.substring(url.lastIndexOf("."));
+
+                        Map<String,String> map = new HashMap<>();
+                        map.put("fileUrl",url + "?x-oss-process=image/resize,l_1024,limit_1");
+                        map.put("fileName", member.getCardNo() + "-" + (i+1) + ext);
+
+                        fileList.add(map);
+                    }
+                }
+            }
+
+            OutputStream output = response.getOutputStream();
+
+            OSSUtil.batchDownload(fileList,output);
+
+            output.flush();
+            output.close();
+
+            request.getSession().setAttribute("lastDownloadIdCardTime",System.currentTimeMillis());
+        }
+        catch (Exception ex){
+            log.error(ex.getMessage(),ex);
+        }
+    }
 }

+ 4 - 4
picc-enterprise-server/src/main/java/com/jpsoft/picc/modules/auth/controller/CompanyMemberController.java

@@ -350,10 +350,10 @@ public class CompanyMemberController {
                 String name = array[1].toString();
                 String cardType = array[2].toString();
                 String cardNo = array[3].toString();
-                Boolean sex = Convert.toBool(array[3]);
-                int age = Convert.toInt(array[3]);
-                String jobsId = array[3].toString();
-                String healthStatus = array[3].toString();
+                Boolean sex = Convert.toBool(array[4]);
+                int age = Convert.toInt(array[5]);
+                String jobsId = array[6].toString();
+                String healthStatus = array[7].toString();
 
                 companyMember.setId(UUID.randomUUID().toString());
                 if(StringUtils.isNotEmpty(company.getId())) companyMember.setCompanyId(company.getId());

+ 37 - 18
picc-enterprise-server/src/main/java/com/jpsoft/picc/modules/auth/controller/InsurancePolicyController.java

@@ -1,6 +1,7 @@
 package com.jpsoft.picc.modules.auth.controller;
 
 import com.github.pagehelper.Page;
+import com.jpsoft.picc.config.CasConfig;
 import com.jpsoft.picc.modules.auth.dto.AcceptInsuranceDTO;
 import com.jpsoft.picc.modules.auth.dto.InsuranceApplicationDTO;
 import com.jpsoft.picc.modules.auth.dto.InsuranceJobsDTO;
@@ -28,6 +29,7 @@ import org.joda.time.Interval;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.format.annotation.DateTimeFormat;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
@@ -79,30 +81,47 @@ public class InsurancePolicyController {
     @Autowired
     private UserService userService;
 
-    @ApiOperation(value="查看附件")
-    @RequestMapping(value = "attachmentList",method = RequestMethod.POST)
+    @ResponseBody
+    @ApiOperation(value="附件列表")
+    @RequestMapping(value = "attachmentList",method = RequestMethod.GET)
     @ApiImplicitParams({
-            @ApiImplicitParam(name = "id",value = "编号", required = true, paramType = "form",dataType = "String")
+            @ApiImplicitParam(name = "policyId",value = "投保单编号", required = true, paramType = "query"),
     })
-    public MessageResult<String> attachmentList(@RequestParam(value="id",defaultValue="") String id){
-        MessageResult<String> msgResult = new MessageResult<>();
+    public MessageResult<List> attachmentList(String policyId,HttpServletRequest request){
+        MessageResult<List> msgResult = new MessageResult<>();
 
         try {
-            InsurancePolicy insurancePolicy = insurancePolicyService.get(id);
-
-            if (insurancePolicy != null) {
-                msgResult.setResult(true);
-                msgResult.setData(insurancePolicy.getInsurancePolicyFile());
-            } else {
-                msgResult.setResult(false);
-                msgResult.setMessage("数据库不存在该记录!");
-            }
-        }
-        catch(Exception ex){
-            log.error(ex.getMessage(),ex);
+            AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();
+            String path = request.getContextPath();
+            String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
 
-            msgResult.setResult(false);
+            Company company = companyService.findByCreateBy(principal.getName());
+
+            List<Map> mapList = new ArrayList<>();
+
+            Map<String,String> map1 = new HashMap<>();
+
+            String url = company.getUsccFiles();
+
+            map1.put("type","营业执照");
+            map1.put("title", "营业执照" + url.substring(url.lastIndexOf(".")));
+            map1.put("url", url);
+
+            mapList.add(map1);
+
+            Map<String,String> map2 = new HashMap<>();
+            map2.put("type","身份证");
+            map2.put("title","身份证.zip");
+            map2.put("url",basePath + "auth/attachment/downloadIdCardZip?policyId=" + policyId);
+
+            mapList.add(map2);
+
+            msgResult.setData(mapList);
+            msgResult.setResult(true);
+        }
+        catch (Exception ex){
             msgResult.setMessage(ex.getMessage());
+            msgResult.setResult(false);
         }
 
         return msgResult;

+ 4 - 4
picc-enterprise-server/src/main/java/com/jpsoft/picc/modules/auth/controller/InsurancePolicyUserController.java

@@ -267,10 +267,10 @@ public class InsurancePolicyUserController {
                 String name = array[1].toString();
                 String cardType = array[2].toString();
                 String cardNo = array[3].toString();
-                Boolean sex = Convert.toBool(array[3]);
-                int age = Convert.toInt(array[3]);
-                String jobsId = array[3].toString();
-                String healthStatus = array[3].toString();
+                Boolean sex = Convert.toBool(array[4]);
+                int age = Convert.toInt(array[5]);
+                String jobsId = array[6].toString();
+                String healthStatus = array[7].toString();
 
                 Map<String,Object> searchParams = new HashMap<>();
                 searchParams.put("companyId",company.getId());

+ 1 - 0
pom.xml

@@ -19,6 +19,7 @@
         <module>picc-admin-server</module>
         <module>picc-common</module>
         <module>picc-enterprise-server</module>
+        <module>weixin-middleware</module>
     </modules>
     <properties>
         <java.version>1.8</java.version>

+ 155 - 0
weixin-middleware/pom.xml

@@ -0,0 +1,155 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>picc</artifactId>
+        <groupId>com.jpsoft</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>weixin-middleware</artifactId>
+    <packaging>war</packaging>
+
+    <properties>
+        <swagger2.version>2.7.0</swagger2.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-tomcat</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.junit.vintage</groupId>
+                    <artifactId>junit-vintage-engine</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+
+        <!-- swagger ui begin-->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>${swagger2.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>${swagger2.version}</version>
+        </dependency>
+        <!-- swagger ui end-->
+
+
+        <!--logging start-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-logging</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.lazyluke</groupId>
+            <artifactId>log4jdbc-remix</artifactId>
+            <version>0.2.7</version>
+        </dependency>
+        <!--logging end-->
+
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+    </dependencies>
+
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <fork>true</fork>
+                    <addResources>true</addResources>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>2.16</version>
+                <configuration>
+                    <includes>
+                        <include>**/*TestForPack.java</include>
+                    </includes>
+                    <argLine>-Xmx256M</argLine>
+                </configuration>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.maven.surefire</groupId>
+                        <artifactId>surefire-junit47</artifactId>
+                        <version>2.16</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+    <profiles>
+        <profile>
+            <id>dev</id>
+            <dependencies>
+                <dependency>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-tomcat</artifactId>
+                </dependency>
+            </dependencies>
+            <properties>
+                <active.profile>dev</active.profile>
+            </properties>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+        </profile>
+        <profile>
+            <id>test</id>
+            <dependencies>
+                <dependency>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-tomcat</artifactId>
+                    <scope>provided</scope>
+                </dependency>
+            </dependencies>
+            <properties>
+                <active.profile>test</active.profile>
+            </properties>
+        </profile>
+        <profile>
+            <id>production</id>
+            <properties>
+                <active.profile>production</active.profile>
+            </properties>
+            <dependencies>
+                <dependency>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-tomcat</artifactId>
+                </dependency>
+            </dependencies>
+        </profile>
+    </profiles>
+</project>

+ 18 - 0
weixin-middleware/src/main/java/com/jpsoft/weixin/WeixinMiddlewareApplication.java

@@ -0,0 +1,18 @@
+package com.jpsoft.weixin;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+@SpringBootApplication
+public class WeixinMiddlewareApplication extends SpringBootServletInitializer {
+    public static void main(String[] args) {
+        SpringApplication.run(WeixinMiddlewareApplication.class, args);
+    }
+
+    @Override
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
+        return builder.sources(WeixinMiddlewareApplication.class);
+    }
+}

+ 120 - 0
weixin-middleware/src/main/java/com/jpsoft/weixin/config/RedisConfig.java

@@ -0,0 +1,120 @@
+package com.jpsoft.weixin.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CachingConfigurerSupport;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cache.interceptor.KeyGenerator;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.*;
+import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import java.lang.reflect.Method;
+
+@Configuration
+@EnableCaching
+public class RedisConfig extends CachingConfigurerSupport {
+    /**
+     * 注入 RedisConnectionFactory,注意maven中要有redis.clients.jedis
+     */
+    @Autowired
+    RedisConnectionFactory redisConnectionFactory;
+
+    /**
+     * 实例化 RedisTemplate 对象
+     * @return
+     */
+    @Bean
+    public RedisTemplate<String, Object> getRedisTemplate() {
+        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
+        initDomainRedisTemplate(redisTemplate, redisConnectionFactory);
+        return redisTemplate;
+    }
+
+    /**
+     * 设置数据存入 redis 的序列化方式
+     *
+     * @param redisTemplate
+     * @param factory
+     */
+    private void initDomainRedisTemplate(RedisTemplate<String, Object> redisTemplate, RedisConnectionFactory factory) {
+        redisTemplate.setKeySerializer(new StringRedisSerializer());
+        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
+        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
+        redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
+        redisTemplate.setConnectionFactory(factory);
+    }
+
+    @Bean
+    public KeyGenerator keyGenerator() {
+        return new KeyGenerator() {
+            @Override
+            public Object generate(Object target, Method method, Object... params) {
+                StringBuilder sb = new StringBuilder();
+                sb.append(target.getClass().getName());
+                sb.append(method.getName());
+                for (Object obj : params) {
+                    sb.append(obj.toString());
+                }
+
+                return sb.toString();
+            }
+        };
+    }
+
+    /**
+     * 实例化 HashOperations 对象,可以使用 Hash 类型操作
+     *
+     * @param redisTemplate
+     * @return
+     */
+    @Bean
+    public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
+        return redisTemplate.opsForHash();
+    }
+
+    /**
+     * 实例化 ValueOperations 对象,可以使用 String 操作
+     *
+     * @param redisTemplate
+     * @return
+     */
+    @Bean
+    public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
+        return redisTemplate.opsForValue();
+    }
+
+    /**
+     * 实例化 ListOperations 对象,可以使用 List 操作
+     *
+     * @param redisTemplate
+     * @return
+     */
+    @Bean
+    public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
+        return redisTemplate.opsForList();
+    }
+
+    /**
+     * 实例化 SetOperations 对象,可以使用 Set 操作
+     *
+     * @param redisTemplate
+     * @return
+     */
+    @Bean
+    public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
+        return redisTemplate.opsForSet();
+    }
+
+    /**
+     * 实例化 ZSetOperations 对象,可以使用 ZSet 操作
+     *
+     * @param redisTemplate
+     * @return
+     */
+    @Bean
+    public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
+        return redisTemplate.opsForZSet();
+    }
+}

+ 77 - 0
weixin-middleware/src/main/java/com/jpsoft/weixin/config/SwaggerConfig.java

@@ -0,0 +1,77 @@
+package com.jpsoft.weixin.config;
+
+import io.swagger.annotations.Api;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.ApiKey;
+import springfox.documentation.service.AuthorizationScope;
+import springfox.documentation.service.SecurityReference;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spi.service.contexts.SecurityContext;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Configuration
+@EnableSwagger2
+public class SwaggerConfig {
+    @Bean
+    public Docket createRestApi() {
+        return new Docket(DocumentationType.SWAGGER_2)
+                .apiInfo(apiInfo())
+                .select()
+                .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
+                //.apis(RequestHandlerSelectors.withClassAnnotation(Controller.class))
+                .paths(PathSelectors.any())
+                .build()
+                //添加登录认证
+                .securitySchemes(securitySchemes())
+                .securityContexts(securityContexts());
+    }
+
+    private List<ApiKey> securitySchemes() {
+        //设置请求头信息
+        List<ApiKey> result = new ArrayList<>();
+        ApiKey apiKey = new ApiKey("Authorization", "Authorization", "header");
+        result.add(apiKey);
+        return result;
+    }
+
+    private List<SecurityContext> securityContexts() {
+        //设置需要登录认证的路径
+        List<SecurityContext> result = new ArrayList<>();
+        result.add(getContextByPath("/*"));
+        return result;
+    }
+
+    private SecurityContext getContextByPath(String pathRegex){
+        return SecurityContext.builder()
+                .securityReferences(defaultAuth())
+                .forPaths(PathSelectors.regex(pathRegex))
+                .build();
+    }
+
+    private List<SecurityReference> defaultAuth() {
+        List<SecurityReference> result = new ArrayList<>();
+        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
+        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
+        authorizationScopes[0] = authorizationScope;
+        result.add(new SecurityReference("Authorization", authorizationScopes));
+        return result;
+    }
+
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder()
+                .title("后台接口文档")
+                .description("")
+                .termsOfServiceUrl("")
+                .version("1.0")
+                .build();
+    }
+}

+ 17 - 0
weixin-middleware/src/main/java/com/jpsoft/weixin/config/WeixinConfig.java

@@ -0,0 +1,17 @@
+package com.jpsoft.weixin.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConfigurationProperties(prefix = "weixin")
+@Data
+public class WeixinConfig {
+    private String token;
+    private String appId;
+    private String appSecret;
+    private String tokenUrl;
+    private String createQrCodeUrl;
+    private String showQrCodeUrl;
+}

+ 241 - 0
weixin-middleware/src/main/java/com/jpsoft/weixin/controller/WeixinController.java

@@ -0,0 +1,241 @@
+package com.jpsoft.weixin.controller;
+
+import cn.hutool.core.date.DateTime;
+import cn.hutool.json.JSON;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.jpsoft.weixin.config.WeixinConfig;
+import com.jpsoft.weixin.util.WeixinUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.util.EntityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.*;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import java.io.InputStream;
+import java.net.URLEncoder;
+import java.nio.charset.Charset;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+@Api(description = "微信中控")
+@Controller
+@Slf4j
+public class WeixinController {
+    @Autowired
+    private WeixinConfig weixinConfig;
+
+    @Autowired
+    private ValueOperations<String,Object> valueOperations;
+
+    @ApiOperation(value="验证服务器地址的有效性")
+    @GetMapping("/")
+    @ResponseBody
+    public String index(@RequestParam(defaultValue = "") String signature,
+                        @RequestParam(defaultValue = "") String timestamp,
+                        @RequestParam(defaultValue = "") String nonce,
+                        @RequestParam(defaultValue = "") String echostr){
+        log.warn("signature=" + signature);
+        log.warn("timestamp=" + timestamp);
+        log.warn("nonce=" + nonce);
+        log.warn("echostr=" + echostr);
+
+        if (WeixinUtil.checkSignature(weixinConfig.getToken(),signature,timestamp,nonce)){
+            return echostr;
+        }
+        else{
+            return null;
+        }
+    }
+
+    @ApiOperation(value = "基础支持中获取普通access_token")
+    @GetMapping("/token")
+    @ResponseBody
+    public JSONObject getToken(@RequestParam(defaultValue = "client_credential") String grant_type,
+                        @RequestParam(defaultValue = "") String appid,
+                        @RequestParam(defaultValue = "") String secret){
+        String suffix = "_common_token";
+        JSONObject json = (JSONObject)valueOperations.get(appid + suffix);
+
+        if(json==null) {
+            StringBuilder urlBuilder = new StringBuilder();
+
+            urlBuilder.append(weixinConfig.getTokenUrl());
+
+            urlBuilder.append("?").append("grant_type=").append(grant_type);
+            urlBuilder.append("&").append("appid=").append(appid);
+            urlBuilder.append("&").append("secret=").append(secret);
+
+            try {
+                HttpGet httpGet = new HttpGet(urlBuilder.toString());
+
+                CloseableHttpClient httpClient = HttpClientBuilder.create().build();
+
+                CloseableHttpResponse response = httpClient.execute(httpGet);
+
+                HttpEntity entity = response.getEntity();
+
+                String content = EntityUtils.toString(entity);
+
+                json = new JSONObject(content);
+
+                if(json.containsKey("expires_in")){
+                    Long expiresSeconds = json.getLong("expires_in");
+                    valueOperations.set(appid + suffix,json,expiresSeconds - 30, TimeUnit.SECONDS);
+                }
+            } catch (Exception ex) {
+                log.error(ex.getMessage(), ex);
+            }
+        }
+
+        return json;
+    }
+
+    @ApiOperation(value = "处理消息事件")
+    @PostMapping("/")
+    public void processEvent(HttpServletRequest request, HttpServletResponse response){
+
+        try{
+            Map<String,Object> dataMap = WeixinUtil.xmlToMap(request.getInputStream());
+
+            //{Ticket=gQEH8DwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyckZDekV1RHg5SFAxczNwYjF1MWIAAgTX10teAwQsAQAA, CreateTime=1582028776, EventKey=1457, Event=SCAN, ToUserName=gh_b6e865f48dea, FromUserName=op6Frsy4xuXYGqjaJ12Xv5Q-9NtU, MsgType=event}
+            log.warn(dataMap.toString());
+
+            response.setContentType("UTF-8");
+            response.setContentType("text/html; charset=UTF-8");
+            response.setCharacterEncoding("UTF-8");
+
+            String responseText = "success";
+
+            responseText = replyTextMessage(dataMap);
+
+            response.getWriter().print(responseText);
+        }
+        catch (Exception ex){
+            log.error(ex.getMessage(),ex);
+        }
+    }
+
+    private String replyTextMessage(Map dataMap){
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("<xml>");
+        sb.append("<ToUserName><![CDATA[" + dataMap.get("FromUserName") + "]]></ToUserName>");
+        sb.append("<FromUserName><![CDATA["+ dataMap.get("ToUserName") + "]]></FromUserName>");
+        sb.append("<CreateTime>" + DateTime.now().getTime() + "</CreateTime>");
+        sb.append("<MsgType><![CDATA[text]]></MsgType>");
+        sb.append("<Content><![CDATA[你好]]></Content>");
+        sb.append("</xml>");
+
+        return sb.toString();
+    }
+
+    @ResponseBody
+    @ApiOperation(value = "创建二维码")
+    @PostMapping("/qrcode/create")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name="access_token", paramType="query", required=true, value="基础支持access_token"),
+            @ApiImplicitParam(name="expire_seconds", paramType="query", required=true, value="该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。"),
+            @ApiImplicitParam(name="action_name", paramType="query", required=true, value="二维码类型,QR_SCENE为临时的整型参数值,QR_STR_SCENE为临时的字符串参数值,QR_LIMIT_SCENE为永久的整型参数值,QR_LIMIT_STR_SCENE为永久的字符串参数值"),
+            @ApiImplicitParam(name="scene_id", paramType="query", value="场景值ID,临时二维码时为32位非0整型,永久二维码时最大值为100000(目前参数只支持1--100000)"),
+            @ApiImplicitParam(name="scene_str", paramType="query", value="场景值ID(字符串形式的ID),字符串类型,长度限制为1到64")
+    })
+    public JSONObject createQrCode(@RequestParam(name = "access_token") String accessToken,
+                               @RequestParam(name = "expire_seconds",defaultValue = "300") long expireSeconds,
+                               @RequestParam(name = "action_name",defaultValue = "QR_SCENE") String actionName,
+                               @RequestParam(name = "scene_id",required = false) String sceneId,
+                               @RequestParam(name = "scene_str",required = false) String sceneStr){
+        JSONObject resultObj = new JSONObject();
+
+        try {
+            StringBuilder urlBuilder = new StringBuilder();
+
+            urlBuilder.append(weixinConfig.getCreateQrCodeUrl())
+                    .append("?access_token=")
+                    .append(URLEncoder.encode(accessToken,"UTF-8"));
+
+            HttpPost httpPost = new HttpPost(urlBuilder.toString());
+
+            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
+
+            JSONObject jsonObject = new JSONObject();
+            jsonObject.put("expire_seconds", expireSeconds);
+            jsonObject.put("action_name", actionName);
+
+            JSONObject actionInfo = new JSONObject();
+            JSONObject scene = new JSONObject();
+
+            if(StringUtils.isNotEmpty(sceneId)) {
+                scene.put("scene_id", sceneId);
+            }
+
+            if(StringUtils.isNotEmpty(sceneStr)) {
+                scene.put("scene_str", sceneStr);
+            }
+
+            actionInfo.put("scene",scene);
+
+            jsonObject.put("action_info", actionInfo);
+
+            StringEntity entity = new StringEntity(jsonObject.toString(), "utf-8");
+
+            entity.setContentEncoding("UTF-8");
+            entity.setContentType("application/json");//发送json数据需要设置contentType
+            httpPost.setEntity(entity);
+
+            HttpResponse res = httpClient.execute(httpPost);
+
+            if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+                String content = EntityUtils.toString(res.getEntity());// 返回json格式:
+                JSONObject ret = new JSONObject(content);
+
+                if (ret.containsKey("errcode")) {
+                    resultObj.put("result",false);
+                    resultObj.put("message",ret.getStr("errmsg"));
+                    resultObj.put("code",ret.getInt("errcode"));
+                }
+                else {
+                    String ticket = ret.getStr("ticket");
+                    long expire_seconds = ret.getLong("expire_seconds");
+
+                    resultObj.put("data", weixinConfig.getShowQrCodeUrl() + "?ticket=" + URLEncoder.encode(ticket, "UTF-8"));
+                    resultObj.put("result", true);
+                }
+            }
+        }
+        catch (Exception ex){
+            log.error(ex.getMessage(),ex);
+
+            resultObj.put("message",ex.getMessage());
+            resultObj.put("result",false);
+        }
+
+        return resultObj;
+    }
+}

+ 87 - 0
weixin-middleware/src/main/java/com/jpsoft/weixin/util/WeixinUtil.java

@@ -0,0 +1,87 @@
+package com.jpsoft.weixin.util;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class WeixinUtil {
+
+    public static boolean checkSignature(String token,String signature, String timestamp, String nonce) {
+        String[] arr = new String[] { token, timestamp, nonce };
+
+        String content = Arrays.stream(arr)
+                .sorted(Comparator.naturalOrder())
+                .collect(Collectors.joining());
+
+        MessageDigest md = null;
+        String tmpStr = null;
+ 
+        try {
+            md = MessageDigest.getInstance("SHA-1");
+            // 将三个参数字符串拼接成一个字符串进行sha1加密
+            byte[] digest = md.digest(content.getBytes("UTF-8"));
+
+            StringBuffer hexstr = new StringBuffer();
+
+            String shaHex = "";
+
+            for (int i = 0; i < digest.length; i++) {
+                shaHex = Integer.toHexString(digest[i] & 0xFF);
+                if (shaHex.length() < 2) {
+                    hexstr.append(0);
+                }
+                hexstr.append(shaHex);
+            }
+
+            tmpStr = hexstr.toString();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        // 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
+        return signature.equals(tmpStr);
+    }
+
+    public static Map<String,Object> xmlToMap(InputStream inputStream) throws Exception {
+        Map<String,Object> dataMap = new HashMap<>();
+
+        // 创建sax解析工厂
+        SAXParserFactory factory = SAXParserFactory.newInstance();
+        // 创建sax转换工具
+        SAXParser saxParser = factory.newSAXParser();
+
+        saxParser.parse(inputStream,new DefaultHandler(){
+            private String tagName;
+
+            @Override
+            public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+                tagName = qName;
+            }
+
+            @Override
+            public void endElement(String uri, String localName, String qName) throws SAXException {
+                tagName = null;
+            }
+
+            @Override
+            public void characters(char[] ch, int start, int length) throws SAXException {
+                if(tagName!=null){
+                    String content = new String(ch,start,length);
+                    dataMap.put(tagName,content);
+                }
+            }
+        });
+
+        return dataMap;
+    }
+}

+ 38 - 0
weixin-middleware/src/main/resources/application-dev.yml

@@ -0,0 +1,38 @@
+spring:
+  devtools:
+    add-properties: false
+    restart:
+      enabled: true
+  redis:
+    # Redis数据库索引(默认为0)
+    database: 1
+    # Redis服务器地址
+    host: 127.0.0.1
+    # Redis服务器连接端口
+    port: 6379
+    # Redis服务器连接密码(默认为空)
+    password:
+    # 连接池最大连接数(使用负值表示没有限制)
+    pool:
+      max-active: 8
+      # 连接池最大阻塞等待时间(使用负值表示没有限制)
+      max-wait: -1
+      # 连接池中的最大空闲连接
+      max-idle: 8
+      # 连接池中的最小空闲连接
+      min-idle: 0
+      # 连接超时时间(毫秒)
+      timeout: 0
+
+logger:
+  level: WARN
+  dir: D:\\Logs\\picc\\weixin-middleware\\
+
+weixin:
+  appId: wxc0ddd6a415c535d9
+  appSecret: 042fe6c9c970c1d9fe585dccfca89221
+  token: weixin
+  tokenUrl: "https://api.weixin.qq.com/cgi-bin/token"
+  refreshOAuth2TokenUrl: "https://api.weixin.qq.com/sns/oauth2/refresh_token"
+  createQrCodeUrl: "https://api.weixin.qq.com/cgi-bin/qrcode/create"
+  showQrCodeUrl: "https://mp.weixin.qq.com/cgi-bin/showqrcode"

+ 9 - 0
weixin-middleware/src/main/resources/application-test.yml

@@ -0,0 +1,9 @@
+spring:
+  devtools:
+    add-properties: false
+    restart:
+      enabled: true
+
+logger:
+  level: WARN
+  dir: C:\\Logs\\picc\\weixin-middleware\\

+ 15 - 0
weixin-middleware/src/main/resources/application.yml

@@ -0,0 +1,15 @@
+server:
+  port: 8086
+  servlet:
+    context-path: /weixin-middleware
+
+spring:
+  http:
+    multipart:
+      max-request-size: 20MB
+      max-file-size: 20MB
+  devtools:
+    restart:
+      enabled: true
+  profiles:
+    active: @active.profile@

+ 55 - 0
weixin-middleware/src/main/resources/logback-spring.xml

@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <include resource="org/springframework/boot/logging/logback/base.xml"/>
+    <!--
+    官方文档指明,需要使用<springProperty>,才可使用application.properties(或application.yml)中的值
+    -->
+    <springProperty scope="context" name="loggerLevel" source="logger.level"/>
+    <springProperty scope="context" name="loggerPath" source="logger.dir"/>
+    <property name="pattern" value="%date %level [%thread] %logger{36} [%file : %line] %msg%n"></property>
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${pattern}</pattern>
+        </encoder>
+    </appender>
+    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${loggerPath}/logfile.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${loggerPath}/logfile.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <MaxHistory>30</MaxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${pattern}</pattern>
+        </encoder>
+    </appender>
+    <!--
+    直接用maven的变量是@...@,用spring的变量是${...}
+    -->
+    <springProfile name="dev">
+        <!--root的level不能用变量-->
+        <logger name="jdbc" additivity="false" level="WARN">
+            <appender-ref ref="STDOUT" />
+        </logger>
+        <logger name="jdbc.sqltiming" additivity="false" level="ON">
+            <appender-ref ref="STDOUT" />
+        </logger>
+    </springProfile>
+    <springProfile name="remote">
+        <root level="WARN">
+            <appender-ref ref="STDOUT" />
+            <appender-ref ref="FILE" />
+        </root>
+    </springProfile>
+    <springProfile name="test">
+        <root level="WARN">
+            <appender-ref ref="STDOUT" />
+            <appender-ref ref="FILE" />
+        </root>
+    </springProfile>
+    <springProfile name="production">
+        <root level="WARN">
+            <appender-ref ref="STDOUT" />
+            <appender-ref ref="FILE" />
+        </root>
+    </springProfile>
+</configuration>