Ver Fonte

增加微信小程序管理接口、开放接口;增加SMS开放接口

luoshi há 2 anos atrás
pai
commit
5a444fbb29

+ 8 - 0
pom.xml

@@ -38,6 +38,14 @@
             <groupId>com.qmth.boot</groupId>
             <artifactId>core-fss</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.qmth.boot</groupId>
+            <artifactId>core-concurrent</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.qmth.boot</groupId>
+            <artifactId>core-sms</artifactId>
+        </dependency>
         <dependency>
             <groupId>com.qmth.boot</groupId>
             <artifactId>core-solar</artifactId>

+ 2 - 0
src/main/java/com/qmth/ops/api/OpsApiApplication.java

@@ -1,5 +1,6 @@
 package com.qmth.ops.api;
 
+import com.qmth.boot.core.retrofit.annotatioin.RetrofitScan;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -8,6 +9,7 @@ import org.springframework.context.annotation.ComponentScan;
 @SpringBootApplication
 @ComponentScan("com.qmth.ops")
 @MapperScan("com.qmth.ops.biz")
+@RetrofitScan("com.qmth.ops.biz.wxapp")
 public class OpsApiApplication {
 
     public static void main(String[] args) {

+ 41 - 0
src/main/java/com/qmth/ops/api/controller/admin/WxappController.java

@@ -0,0 +1,41 @@
+package com.qmth.ops.api.controller.admin;
+
+import com.qmth.ops.api.constants.OpsApiConstants;
+import com.qmth.ops.biz.domain.Wxapp;
+import com.qmth.ops.biz.query.WxappQuery;
+import com.qmth.ops.biz.service.WxappService;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@RestController
+@RequestMapping(OpsApiConstants.ADMIN_URI_PREFIX + "/wxapp")
+public class WxappController {
+
+    @Resource
+    private WxappService wxappService;
+
+    @PostMapping("/query")
+    public WxappQuery query(WxappQuery query) {
+        return wxappService.findByQuery(query);
+    }
+
+    @PostMapping("/list")
+    public List<Wxapp> list(WxappQuery query) {
+        return wxappService.listByQuery(query);
+    }
+
+    @PostMapping("/insert")
+    public Wxapp insert(Wxapp wxapp) {
+        return wxappService.insert(wxapp);
+    }
+
+    @PostMapping("/update")
+    public Wxapp update(Wxapp wxapp) {
+        return wxappService.update(wxapp);
+    }
+
+}

+ 34 - 0
src/main/java/com/qmth/ops/api/controller/open/OpenWxappController.java

@@ -0,0 +1,34 @@
+package com.qmth.ops.api.controller.open;
+
+import com.qmth.boot.api.annotation.Aac;
+import com.qmth.boot.api.annotation.BOOL;
+import com.qmth.boot.core.solar.model.WxappAccessToken;
+import com.qmth.boot.core.solar.model.WxappSession;
+import com.qmth.boot.tools.signature.SignatureType;
+import com.qmth.ops.api.constants.OpsApiConstants;
+import com.qmth.ops.biz.service.WxappService;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+@RestController
+@RequestMapping(OpsApiConstants.OPEN_URI_PREFIX + "/wxapp")
+@Aac(auth = BOOL.TRUE, signType = SignatureType.SECRET)
+public class OpenWxappController {
+
+    @Resource
+    private WxappService wxappService;
+
+    @PostMapping("/access_token")
+    public WxappAccessToken getAccessToken(@RequestParam String appId) {
+        return wxappService.getAccessToken(appId);
+    }
+
+    @PostMapping("/session_by_code")
+    public WxappSession getSessionByCode(@RequestParam String appId, @RequestParam String code) {
+        return wxappService.getSessionByCode(appId, code).output();
+    }
+}

+ 29 - 0
src/main/java/com/qmth/ops/api/controller/sms/SmsController.java

@@ -0,0 +1,29 @@
+package com.qmth.ops.api.controller.sms;
+
+import com.qmth.boot.api.annotation.Aac;
+import com.qmth.boot.api.annotation.BOOL;
+import com.qmth.boot.core.sms.api.SmsApiClient;
+import com.qmth.boot.core.sms.model.SmsConstants;
+import com.qmth.boot.core.sms.model.SmsSendRequest;
+import com.qmth.boot.core.sms.model.SmsSendResponse;
+import com.qmth.boot.tools.signature.SignatureType;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+@RestController
+@Aac(auth = BOOL.TRUE, signType = SignatureType.SECRET)
+public class SmsController {
+
+    @Resource
+    private SmsApiClient smsApiClient;
+
+    @RequestMapping(SmsConstants.API_PATH_SEND_SMS)
+    public SmsSendResponse sendSms(@RequestBody @Validated SmsSendRequest request) {
+        return smsApiClient.sendSms(request);
+    }
+
+}

+ 3 - 1
src/main/java/com/qmth/ops/api/security/OpenAuthorizationService.java

@@ -2,6 +2,7 @@ package com.qmth.ops.api.security;
 
 import com.qmth.boot.core.security.annotation.AuthorizationComponent;
 import com.qmth.boot.core.security.service.AuthorizationService;
+import com.qmth.boot.core.sms.model.SmsConstants;
 import com.qmth.boot.tools.signature.SignatureType;
 import com.qmth.ops.api.constants.OpsApiConstants;
 import com.qmth.ops.biz.domain.Deploy;
@@ -9,7 +10,8 @@ import com.qmth.ops.biz.service.DeployService;
 
 import javax.annotation.Resource;
 
-@AuthorizationComponent(prefix = OpsApiConstants.OPEN_URI_PREFIX, type = SignatureType.SECRET)
+@AuthorizationComponent(prefix = { OpsApiConstants.OPEN_URI_PREFIX,
+        SmsConstants.API_PATH_PREFIX }, type = SignatureType.SECRET)
 public class OpenAuthorizationService implements AuthorizationService<AccessDeploy>, OpsApiConstants {
 
     @Resource

+ 8 - 0
src/main/java/com/qmth/ops/biz/dao/WxappDao.java

@@ -0,0 +1,8 @@
+package com.qmth.ops.biz.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.qmth.ops.biz.domain.Wxapp;
+
+public interface WxappDao extends BaseMapper<Wxapp> {
+
+}

+ 81 - 0
src/main/java/com/qmth/ops/biz/domain/Wxapp.java

@@ -0,0 +1,81 @@
+package com.qmth.ops.biz.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+@TableName(value = "wxapp", autoResultMap = true)
+public class Wxapp {
+
+    @TableId(type = IdType.INPUT)
+    private String id;
+
+    private String name;
+
+    private String secret;
+
+    private String accessToken;
+
+    private Long expireTime;
+
+    private Long createTime;
+
+    private Long updateTime;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getSecret() {
+        return secret;
+    }
+
+    public void setSecret(String secret) {
+        this.secret = secret;
+    }
+
+    public String getAccessToken() {
+        return accessToken;
+    }
+
+    public void setAccessToken(String accessToken) {
+        this.accessToken = accessToken;
+    }
+
+    public Long getExpireTime() {
+        return expireTime;
+    }
+
+    public void setExpireTime(Long expireTime) {
+        this.expireTime = expireTime;
+    }
+
+    public Long getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Long createTime) {
+        this.createTime = createTime;
+    }
+
+    public Long getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Long updateTime) {
+        this.updateTime = updateTime;
+    }
+
+}

+ 55 - 0
src/main/java/com/qmth/ops/biz/query/WxappQuery.java

@@ -0,0 +1,55 @@
+package com.qmth.ops.biz.query;
+
+import com.qmth.boot.mybatis.query.BaseQuery;
+import com.qmth.ops.biz.domain.Wxapp;
+import org.springframework.validation.annotation.Validated;
+
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+
+@Validated
+public class WxappQuery extends BaseQuery<Wxapp> {
+
+    private static final long serialVersionUID = 5914856418255713740L;
+
+    private String id;
+
+    private String name;
+
+    private String nameStartWith;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getNameStartWith() {
+        return nameStartWith;
+    }
+
+    public void setNameStartWith(String nameStartWith) {
+        this.nameStartWith = nameStartWith;
+    }
+
+    @Min(1)
+    public long getPageNumber() {
+        return super.getPageNumber();
+    }
+
+    @Min(1)
+    @Max(100)
+    public long getPageSize() {
+        return super.getPageSize();
+    }
+}

+ 135 - 0
src/main/java/com/qmth/ops/biz/service/WxappService.java

@@ -0,0 +1,135 @@
+package com.qmth.ops.biz.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qmth.boot.core.concurrent.service.ConcurrentService;
+import com.qmth.boot.core.exception.ParameterException;
+import com.qmth.boot.core.solar.model.WxappAccessToken;
+import com.qmth.ops.biz.dao.WxappDao;
+import com.qmth.ops.biz.domain.Wxapp;
+import com.qmth.ops.biz.query.WxappQuery;
+import com.qmth.ops.biz.wxapp.api.WxappApiClient;
+import com.qmth.ops.biz.wxapp.dto.AccessTokenResult;
+import com.qmth.ops.biz.wxapp.dto.Code2SessionResult;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.concurrent.locks.Lock;
+
+@Service
+public class WxappService extends ServiceImpl<WxappDao, Wxapp> {
+
+    private static final String WXAPP_ACCESS_TOKEN_KEY = "wxapp:access_token:";
+
+    private static final String GRANT_TYPE_ACCESS_TOKEN = "client_credential";
+
+    private static final String GRANT_TYPE_CODE_2_SESSION = "authorization_code";
+
+    @Resource
+    private WxappDao wxappDao;
+
+    @Resource
+    private WxappApiClient wxappApiClient;
+
+    @Resource
+    private ConcurrentService concurrentService;
+
+    public Wxapp findById(String id) {
+        return wxappDao.selectById(id);
+    }
+
+    public WxappQuery findByQuery(WxappQuery query) {
+        return wxappDao.selectPage(query, buildQuery(query));
+    }
+
+    public List<Wxapp> listByQuery(WxappQuery query) {
+        return wxappDao.selectList(buildQuery(query));
+    }
+
+    @Transactional
+    public Wxapp insert(Wxapp wxapp) {
+        wxapp.setCreateTime(System.currentTimeMillis());
+        wxapp.setUpdateTime(wxapp.getCreateTime());
+        if (wxappDao.insert(wxapp) == 1) {
+            return wxapp;
+        } else {
+            return null;
+        }
+    }
+
+    @Transactional
+    public Wxapp update(Wxapp wxapp) {
+        Wxapp previous = wxappDao.selectById(wxapp.getId());
+        if (previous != null) {
+            if (wxapp.getName() != null) {
+                previous.setName(wxapp.getName());
+            }
+            if (wxapp.getSecret() != null) {
+                previous.setSecret(wxapp.getSecret());
+            }
+            previous.setUpdateTime(System.currentTimeMillis());
+            if (wxappDao.updateById(previous) == 1) {
+                return previous;
+            }
+        }
+        return null;
+    }
+
+    private LambdaQueryWrapper<Wxapp> buildQuery(WxappQuery query) {
+        return new QueryWrapper<Wxapp>().lambda().eq(query.getId() != null, Wxapp::getId, query.getId())
+                .eq(query.getName() != null, Wxapp::getName, query.getName())
+                .likeRight(query.getNameStartWith() != null, Wxapp::getName, query.getNameStartWith());
+    }
+
+    public WxappAccessToken getAccessToken(String appId) {
+        Wxapp wxapp = findById(appId);
+        if (wxapp == null) {
+            throw new ParameterException("Invalid appId");
+        }
+        String key = WXAPP_ACCESS_TOKEN_KEY.concat(wxapp.getId());
+        WxappAccessToken obj = new WxappAccessToken();
+        if (wxapp.getAccessToken() != null && wxapp.getExpireTime() != null && wxapp.getExpireTime() > System
+                .currentTimeMillis()) {
+            obj.setAccessToken(wxapp.getAccessToken());
+            obj.setExpireTime(wxapp.getExpireTime());
+        } else {
+            Lock lock = concurrentService.getLock(key);
+            lock.lock();
+            try {
+                AccessTokenResult result = wxappApiClient
+                        .getAccessToken(wxapp.getId(), wxapp.getSecret(), GRANT_TYPE_ACCESS_TOKEN);
+                if (result.success()) {
+                    //强制提前60秒更新
+                    result.setExpireSecond(result.getExpireSecond() - 60);
+                    obj = result.output();
+                    wxapp.setAccessToken(obj.getAccessToken());
+                    wxapp.setExpireTime(obj.getExpireTime());
+                    wxappDao.updateById(wxapp);
+                } else {
+                    throw result.exception();
+                }
+            } finally {
+                lock.unlock();
+            }
+        }
+        return obj;
+    }
+
+    public Code2SessionResult getSessionByCode(String appId, String code) {
+        Wxapp wxapp = findById(appId);
+        if (wxapp == null) {
+            throw new ParameterException("Invalid WxappId");
+        }
+        Code2SessionResult result = wxappApiClient
+                .code2session(wxapp.getId(), wxapp.getSecret(), code, GRANT_TYPE_CODE_2_SESSION);
+        if (result.success()) {
+            return result;
+        } else {
+            throw result.exception();
+        }
+    }
+}
+

+ 19 - 0
src/main/java/com/qmth/ops/biz/wxapp/api/WxappApiClient.java

@@ -0,0 +1,19 @@
+package com.qmth.ops.biz.wxapp.api;
+
+import com.qmth.boot.core.retrofit.annotatioin.RetrofitClient;
+import com.qmth.ops.biz.wxapp.dto.AccessTokenResult;
+import com.qmth.ops.biz.wxapp.dto.Code2SessionResult;
+import retrofit2.http.GET;
+import retrofit2.http.Query;
+
+@RetrofitClient(configuration = WxappApiConfiguration.class)
+public interface WxappApiClient {
+
+    @GET("cgi-bin/token")
+    AccessTokenResult getAccessToken(@Query("appid") String appId, @Query("secret") String secret,
+            @Query("grant_type") String grantType);
+
+    @GET("sns/jscode2session")
+    Code2SessionResult code2session(@Query("appid") String appId, @Query("secret") String secret,
+            @Query("js_code") String code, @Query("grant_type") String grantType);
+}

+ 17 - 0
src/main/java/com/qmth/ops/biz/wxapp/api/WxappApiConfiguration.java

@@ -0,0 +1,17 @@
+package com.qmth.ops.biz.wxapp.api;
+
+import com.qmth.boot.core.retrofit.interfaces.CustomizeRetrofitConfiguration;
+import com.qmth.boot.core.retrofit.interfaces.SignatureProvider;
+import org.springframework.stereotype.Component;
+
+@Component
+public class WxappApiConfiguration implements CustomizeRetrofitConfiguration {
+
+    public String getBaseUrl() {
+        return "https://api.weixin.qq.com/";
+    }
+
+    public SignatureProvider getSignature() {
+        return null;
+    }
+}

+ 62 - 0
src/main/java/com/qmth/ops/biz/wxapp/dto/AccessTokenResult.java

@@ -0,0 +1,62 @@
+package com.qmth.ops.biz.wxapp.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.qmth.boot.core.solar.model.WxappAccessToken;
+
+public class AccessTokenResult implements BaseResult {
+
+    @JsonProperty("access_token")
+    private String accessToken;
+
+    @JsonProperty("expires_in")
+    private Long expireSecond;
+
+    @JsonProperty("errcode")
+    private Long errorCode;
+
+    @JsonProperty("errmsg")
+    private String errorMessage;
+
+    public String getAccessToken() {
+        return accessToken;
+    }
+
+    public void setAccessToken(String accessToken) {
+        this.accessToken = accessToken;
+    }
+
+    public Long getExpireSecond() {
+        return expireSecond;
+    }
+
+    public void setExpireSecond(Long expireSecond) {
+        this.expireSecond = expireSecond;
+    }
+
+    @Override
+    public Long getErrorCode() {
+        return errorCode;
+    }
+
+    @Override
+    public void setErrorCode(Long errorCode) {
+        this.errorCode = errorCode;
+    }
+
+    @Override
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    @Override
+    public void setErrorMessage(String errorMessage) {
+        this.errorMessage = errorMessage;
+    }
+
+    public WxappAccessToken output() {
+        WxappAccessToken result = new WxappAccessToken();
+        result.setAccessToken(accessToken);
+        result.setExpireTime(System.currentTimeMillis() + expireSecond * 1000);
+        return result;
+    }
+}

+ 24 - 0
src/main/java/com/qmth/ops/biz/wxapp/dto/BaseResult.java

@@ -0,0 +1,24 @@
+package com.qmth.ops.biz.wxapp.dto;
+
+import com.qmth.boot.core.exception.StatusException;
+import org.apache.commons.lang3.StringUtils;
+
+public interface BaseResult {
+
+    Long getErrorCode();
+
+    void setErrorCode(Long errorCode);
+
+    String getErrorMessage();
+
+    void setErrorMessage(String errorMessage);
+
+    default boolean success() {
+        return getErrorCode() == null || getErrorCode() == 0;
+    }
+
+    default StatusException exception() {
+        return new StatusException(201, "wxapp api error",
+                getErrorCode() + ":" + StringUtils.trimToEmpty(getErrorMessage()), null);
+    }
+}

+ 75 - 0
src/main/java/com/qmth/ops/biz/wxapp/dto/Code2SessionResult.java

@@ -0,0 +1,75 @@
+package com.qmth.ops.biz.wxapp.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.qmth.boot.core.solar.model.WxappSession;
+
+public class Code2SessionResult implements BaseResult {
+
+    @JsonProperty("openid")
+    private String openId;
+
+    @JsonProperty("session_key")
+    private String sessionKey;
+
+    @JsonProperty("unionid")
+    private String unionId;
+
+    @JsonProperty("errcode")
+    private Long errorCode;
+
+    @JsonProperty("errmsg")
+    private String errorMessage;
+
+    public String getOpenId() {
+        return openId;
+    }
+
+    public void setOpenId(String openId) {
+        this.openId = openId;
+    }
+
+    public String getSessionKey() {
+        return sessionKey;
+    }
+
+    public void setSessionKey(String sessionKey) {
+        this.sessionKey = sessionKey;
+    }
+
+    public String getUnionId() {
+        return unionId;
+    }
+
+    public void setUnionId(String unionId) {
+        this.unionId = unionId;
+    }
+
+    @Override
+    public Long getErrorCode() {
+        return errorCode;
+    }
+
+    @Override
+    public void setErrorCode(Long errorCode) {
+        this.errorCode = errorCode;
+    }
+
+    @Override
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    @Override
+    public void setErrorMessage(String errorMessage) {
+        this.errorMessage = errorMessage;
+    }
+
+    public WxappSession output() {
+        WxappSession session = new WxappSession();
+        session.setOpenId(openId);
+        session.setSessionKey(sessionKey);
+        session.setUnionId(unionId);
+        return session;
+    }
+
+}

+ 5 - 0
src/main/resources/application.properties

@@ -6,4 +6,9 @@ com.qmth.datasource.url=jdbc:mysql://192.168.10.83:3306/ops_db?useUnicode=true&c
 com.qmth.datasource.username=scan
 com.qmth.datasource.password=scan
 
+com.qmth.fss.config=oss://key:secret@solar.oss-api.qmth.com.cn
+com.qmth.fss.server=http://oss-file.qmth.com.cn/solar
+
+com.qmth.sms.server=http://127.0.0.1:8090
+
 admin.private-key=