客户端app
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
package org.app;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
@MapperScan("org.app.dao")
|
||||
public class AppServiceApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(AppServiceApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.app.common;
|
||||
|
||||
|
||||
import org.app.exception.ApplicationExceptionEnum;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
public enum BaseErrorCode implements ApplicationExceptionEnum {
|
||||
|
||||
SUCCESS(200,"success"),
|
||||
SYSTEM_ERROR(90000,"服务器内部错误,请联系管理员"),
|
||||
PARAMETER_ERROR(90001,"参数校验错误"),
|
||||
|
||||
|
||||
;
|
||||
|
||||
private int code;
|
||||
private String error;
|
||||
|
||||
BaseErrorCode(int code, String error){
|
||||
this.code = code;
|
||||
this.error = error;
|
||||
}
|
||||
public int getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return this.error;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package org.app.common;
|
||||
|
||||
import org.app.exception.ApplicationExceptionEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ResponseVO<T> {
|
||||
|
||||
private int code;
|
||||
|
||||
private String msg;
|
||||
|
||||
private T data;
|
||||
|
||||
public static ResponseVO successResponse(Object data) {
|
||||
return new ResponseVO(200, "success", data);
|
||||
}
|
||||
|
||||
public static ResponseVO successResponse() {
|
||||
return new ResponseVO(200, "success");
|
||||
}
|
||||
|
||||
public static ResponseVO errorResponse() {
|
||||
return new ResponseVO(500, "系统内部异常");
|
||||
}
|
||||
|
||||
public static ResponseVO errorResponse(int code, String msg) {
|
||||
return new ResponseVO(code, msg);
|
||||
}
|
||||
|
||||
public static ResponseVO errorResponse(ApplicationExceptionEnum enums) {
|
||||
return new ResponseVO(enums.getCode(), enums.getError());
|
||||
}
|
||||
|
||||
public boolean isOk(){
|
||||
return this.code == 200;
|
||||
}
|
||||
|
||||
|
||||
public ResponseVO(int code, String msg) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
// this.data = null;
|
||||
}
|
||||
|
||||
public ResponseVO success(){
|
||||
this.code = 200;
|
||||
this.msg = "success";
|
||||
return this;
|
||||
}
|
||||
|
||||
public ResponseVO success(T data){
|
||||
this.code = 200;
|
||||
this.msg = "success";
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
30
hs-im-app-server/src/main/java/org/app/config/AppConfig.java
Normal file
30
hs-im-app-server/src/main/java/org/app/config/AppConfig.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package org.app.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "appconfig")
|
||||
public class AppConfig {
|
||||
|
||||
private String imUrl;
|
||||
|
||||
private String imVersion;
|
||||
|
||||
private Integer appId;
|
||||
|
||||
private String adminId;
|
||||
|
||||
private String privateKey;
|
||||
|
||||
private String jwtKey;
|
||||
|
||||
private Integer jwtExpireTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package org.app.config;
|
||||
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "httpclient")
|
||||
public class GlobalHttpClientConfig {
|
||||
private Integer maxTotal; // 最大连接数
|
||||
private Integer defaultMaxPerRoute; // 最大并发链接数
|
||||
private Integer connectTimeout; // 创建链接的最大时间
|
||||
private Integer connectionRequestTimeout; // 链接获取超时时间
|
||||
private Integer socketTimeout; // 数据传输最长时间
|
||||
private boolean staleConnectionCheckEnabled; // 提交时检查链接是否可用
|
||||
|
||||
PoolingHttpClientConnectionManager manager = null;
|
||||
HttpClientBuilder httpClientBuilder = null;
|
||||
|
||||
// 定义httpClient链接池
|
||||
@Bean(name = "httpClientConnectionManager")
|
||||
public PoolingHttpClientConnectionManager getPoolingHttpClientConnectionManager() {
|
||||
return getManager();
|
||||
}
|
||||
|
||||
private PoolingHttpClientConnectionManager getManager() {
|
||||
if (manager != null) {
|
||||
return manager;
|
||||
}
|
||||
manager = new PoolingHttpClientConnectionManager();
|
||||
manager.setMaxTotal(maxTotal); // 设定最大链接数
|
||||
manager.setDefaultMaxPerRoute(defaultMaxPerRoute); // 设定并发链接数
|
||||
return manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实例化连接池,设置连接池管理器。 这里需要以参数形式注入上面实例化的连接池管理器
|
||||
*
|
||||
* @Qualifier 指定bean标签进行注入
|
||||
*/
|
||||
@Bean(name = "httpClientBuilder")
|
||||
public HttpClientBuilder getHttpClientBuilder(
|
||||
@Qualifier("httpClientConnectionManager") PoolingHttpClientConnectionManager httpClientConnectionManager) {
|
||||
|
||||
// HttpClientBuilder中的构造方法被protected修饰,所以这里不能直接使用new来实例化一个HttpClientBuilder,可以使用HttpClientBuilder提供的静态方法create()来获取HttpClientBuilder对象
|
||||
httpClientBuilder = HttpClientBuilder.create();
|
||||
httpClientBuilder.setConnectionManager(httpClientConnectionManager);
|
||||
return httpClientBuilder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 注入连接池,用于获取httpClient
|
||||
*
|
||||
* @param httpClientBuilder
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public CloseableHttpClient getCloseableHttpClient(
|
||||
@Qualifier("httpClientBuilder") HttpClientBuilder httpClientBuilder) {
|
||||
|
||||
return httpClientBuilder.build();
|
||||
}
|
||||
|
||||
public CloseableHttpClient getCloseableHttpClient() {
|
||||
if (httpClientBuilder != null) {
|
||||
return httpClientBuilder.build();
|
||||
}
|
||||
httpClientBuilder = HttpClientBuilder.create();
|
||||
httpClientBuilder.setConnectionManager(getManager());
|
||||
return httpClientBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder是RequestConfig的一个内部类 通过RequestConfig的custom方法来获取到一个Builder对象
|
||||
* 设置builder的连接信息
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean(name = "builder")
|
||||
public RequestConfig.Builder getBuilder() {
|
||||
RequestConfig.Builder builder = RequestConfig.custom();
|
||||
return builder.setConnectTimeout(connectTimeout).setConnectionRequestTimeout(connectionRequestTimeout)
|
||||
.setSocketTimeout(socketTimeout).setStaleConnectionCheckEnabled(staleConnectionCheckEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用builder构建一个RequestConfig对象
|
||||
*
|
||||
* @param builder
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public RequestConfig getRequestConfig(@Qualifier("builder") RequestConfig.Builder builder) {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public Integer getMaxTotal() {
|
||||
return maxTotal;
|
||||
}
|
||||
|
||||
public void setMaxTotal(Integer maxTotal) {
|
||||
this.maxTotal = maxTotal;
|
||||
}
|
||||
|
||||
public Integer getDefaultMaxPerRoute() {
|
||||
return defaultMaxPerRoute;
|
||||
}
|
||||
|
||||
public void setDefaultMaxPerRoute(Integer defaultMaxPerRoute) {
|
||||
this.defaultMaxPerRoute = defaultMaxPerRoute;
|
||||
}
|
||||
|
||||
public Integer getConnectTimeout() {
|
||||
return connectTimeout;
|
||||
}
|
||||
|
||||
public void setConnectTimeout(Integer connectTimeout) {
|
||||
this.connectTimeout = connectTimeout;
|
||||
}
|
||||
|
||||
public Integer getConnectionRequestTimeout() {
|
||||
return connectionRequestTimeout;
|
||||
}
|
||||
|
||||
public void setConnectionRequestTimeout(Integer connectionRequestTimeout) {
|
||||
this.connectionRequestTimeout = connectionRequestTimeout;
|
||||
}
|
||||
|
||||
public Integer getSocketTimeout() {
|
||||
return socketTimeout;
|
||||
}
|
||||
|
||||
public void setSocketTimeout(Integer socketTimeout) {
|
||||
this.socketTimeout = socketTimeout;
|
||||
}
|
||||
|
||||
public boolean isStaleConnectionCheckEnabled() {
|
||||
return staleConnectionCheckEnabled;
|
||||
}
|
||||
|
||||
public void setStaleConnectionCheckEnabled(boolean staleConnectionCheckEnabled) {
|
||||
this.staleConnectionCheckEnabled = staleConnectionCheckEnabled;
|
||||
}
|
||||
}
|
||||
24
hs-im-app-server/src/main/java/org/app/config/WebConfig.java
Normal file
24
hs-im-app-server/src/main/java/org/app/config/WebConfig.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package org.app.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
@Configuration
|
||||
public class WebConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**")
|
||||
.allowedOrigins("*")
|
||||
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
|
||||
.allowCredentials(true)
|
||||
.maxAge(3600)
|
||||
.allowedHeaders("*");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.app.controller;
|
||||
|
||||
import org.app.common.ResponseVO;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: lld
|
||||
* @version: 1.0
|
||||
*/
|
||||
@RestController
|
||||
public class CallbackController {
|
||||
|
||||
private static Logger logger
|
||||
= LoggerFactory.getLogger(CallbackController.class);
|
||||
|
||||
@RequestMapping("/callback")
|
||||
public ResponseVO callback(@RequestBody Object req, String command, Integer appId) {
|
||||
logger.info("{}收到{}回调数据:{}",
|
||||
appId,command, JSONObject.toJSONString(req));
|
||||
return ResponseVO.successResponse();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.app.controller;
|
||||
|
||||
import org.app.common.ResponseVO;
|
||||
import org.app.model.req.LoginReq;
|
||||
import org.app.model.req.RegisterReq;
|
||||
import org.app.service.LoginService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
@RestController
|
||||
@RequestMapping("v1")
|
||||
public class LoginController {
|
||||
|
||||
@Autowired
|
||||
LoginService loginService;
|
||||
|
||||
@RequestMapping("/login")
|
||||
public ResponseVO login(@RequestBody @Validated LoginReq req) {
|
||||
|
||||
return loginService.login(req);
|
||||
}
|
||||
|
||||
@RequestMapping("/register")
|
||||
public ResponseVO register(@RequestBody @Validated RegisterReq req) {
|
||||
return loginService.register(req);
|
||||
}
|
||||
|
||||
}
|
||||
28
hs-im-app-server/src/main/java/org/app/dao/User.java
Normal file
28
hs-im-app-server/src/main/java/org/app/dao/User.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package org.app.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
@Data
|
||||
@TableName("app_user")
|
||||
public class User {
|
||||
|
||||
@TableId
|
||||
private String userId;
|
||||
//用户名
|
||||
private String userName;
|
||||
//密码
|
||||
private String password;
|
||||
//手机号
|
||||
private String mobile;
|
||||
//创建时间
|
||||
private Long createTime;
|
||||
//更新时间
|
||||
private Long updateTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.app.dao.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.app.dao.User;
|
||||
import org.app.model.req.SearchUserReq;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface UserMapper extends BaseMapper<User> {
|
||||
|
||||
|
||||
@Select("<script>" +
|
||||
" select user_id from app_user " +
|
||||
"<if test = 'searchType == 1'> " +
|
||||
" where mobile = #{keyWord} " +
|
||||
" </if>" +
|
||||
" <if test = 'searchType == 2'> " +
|
||||
" where user_name = #{keyWord} " +
|
||||
" </if> " +
|
||||
" </script> ")
|
||||
public List<String> searchUser(SearchUserReq req);
|
||||
|
||||
}
|
||||
43
hs-im-app-server/src/main/java/org/app/enums/ErrorCode.java
Normal file
43
hs-im-app-server/src/main/java/org/app/enums/ErrorCode.java
Normal file
@@ -0,0 +1,43 @@
|
||||
package org.app.enums;
|
||||
|
||||
|
||||
import org.app.exception.ApplicationExceptionEnum;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
public enum ErrorCode implements ApplicationExceptionEnum {
|
||||
|
||||
USER_NOT_EXIST(10000,"用户不存在"),
|
||||
USERNAME_OR_PASSWORD_ERROR(10001,"用户名或密码错误"),
|
||||
MOBILE_IS_REGISTER(10002,"该手机号已注册了用户"),
|
||||
|
||||
REGISTER_ERROR(10003,"注册失败"),
|
||||
|
||||
REPORT_TAG_IS_NOT_EXIST(10004,"举报标签不存在"),
|
||||
|
||||
REDPACKET_IS_NOT_EXIST(10005,"红包不存在"),
|
||||
USER_REDPACKET_IS_OPEN(10006,"用户已抢过该红包"),
|
||||
REDPACKET_IS_EXPIRE(10007,"红包已过期"),
|
||||
REDPACKET_IS_FINISH(10008,"红包已抢完"),
|
||||
REDPACKET_IS_HOT(10009,"红包火爆请稍后再试"),
|
||||
TRYLOCREDPACKET_INTERRUPTED(10010,"抢红包时被中断了"),
|
||||
;
|
||||
|
||||
private int code;
|
||||
private String error;
|
||||
|
||||
ErrorCode(int code, String error){
|
||||
this.code = code;
|
||||
this.error = error;
|
||||
}
|
||||
public int getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return this.error;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.app.enums;
|
||||
|
||||
public enum LoginTypeEnum {
|
||||
|
||||
/**
|
||||
* 1 username;2 验证码 3手机号+验证码
|
||||
*/
|
||||
USERNAME_PASSWORD(1),
|
||||
|
||||
SMS_CODE(2),
|
||||
|
||||
SMS_PASSWORD(3)
|
||||
;
|
||||
|
||||
private int code;
|
||||
|
||||
LoginTypeEnum(int code){
|
||||
this.code=code;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.app.enums;
|
||||
|
||||
public enum RegisterTypeEnum {
|
||||
|
||||
/**
|
||||
* 1 username;2 MOBILE。
|
||||
*/
|
||||
USERNAME(1),
|
||||
|
||||
MOBILE(2),
|
||||
;
|
||||
|
||||
private int code;
|
||||
|
||||
RegisterTypeEnum(int code){
|
||||
this.code=code;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.app.exception;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
public class ApplicationException extends RuntimeException {
|
||||
|
||||
private int code;
|
||||
|
||||
private String error;
|
||||
|
||||
|
||||
public ApplicationException(int code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
this.error = message;
|
||||
}
|
||||
|
||||
public ApplicationException(ApplicationExceptionEnum exceptionEnum) {
|
||||
super(exceptionEnum.getError());
|
||||
this.code = exceptionEnum.getCode();
|
||||
this.error = exceptionEnum.getError();
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* avoid the expensive and useless stack trace for api exceptions
|
||||
* @see Throwable#fillInStackTrace()
|
||||
*/
|
||||
@Override
|
||||
public Throwable fillInStackTrace() {
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.app.exception;
|
||||
|
||||
public interface ApplicationExceptionEnum {
|
||||
|
||||
int getCode();
|
||||
|
||||
String getError();
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package org.app.exception;
|
||||
|
||||
import org.app.common.BaseErrorCode;
|
||||
import org.app.common.ResponseVO;
|
||||
import org.hibernate.validator.internal.engine.path.PathImpl;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.validation.ObjectError;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
|
||||
@ExceptionHandler(value=Exception.class)
|
||||
@ResponseBody
|
||||
public ResponseVO unknowException(Exception e){
|
||||
e.printStackTrace();
|
||||
ResponseVO resultBean =new ResponseVO();
|
||||
resultBean.setCode(BaseErrorCode.SYSTEM_ERROR.getCode());
|
||||
resultBean.setMsg(BaseErrorCode.SYSTEM_ERROR.getError());
|
||||
/**
|
||||
* 未知异常的话,这里写逻辑,发邮件,发短信都可以、、
|
||||
*/
|
||||
return resultBean;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validator 参数校验异常处理
|
||||
*
|
||||
* @param ex
|
||||
* @return
|
||||
*/
|
||||
@ExceptionHandler(value = ConstraintViolationException.class)
|
||||
@ResponseBody
|
||||
public Object handleMethodArgumentNotValidException(ConstraintViolationException ex) {
|
||||
|
||||
Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
|
||||
ResponseVO resultBean =new ResponseVO();
|
||||
resultBean.setCode(BaseErrorCode.PARAMETER_ERROR.getCode());
|
||||
for (ConstraintViolation<?> constraintViolation : constraintViolations) {
|
||||
PathImpl pathImpl = (PathImpl) constraintViolation.getPropertyPath();
|
||||
// 读取参数字段,constraintViolation.getMessage() 读取验证注解中的message值
|
||||
String paramName = pathImpl.getLeafNode().getName();
|
||||
String message = "参数{".concat(paramName).concat("}").concat(constraintViolation.getMessage());
|
||||
resultBean.setMsg(message);
|
||||
|
||||
return resultBean;
|
||||
}
|
||||
resultBean.setMsg(BaseErrorCode.PARAMETER_ERROR.getError() + ex.getMessage());
|
||||
return resultBean;
|
||||
}
|
||||
|
||||
@ExceptionHandler(ApplicationException.class)
|
||||
@ResponseBody
|
||||
public Object applicationExceptionHandler(ApplicationException e) {
|
||||
// 使用公共的结果类封装返回结果, 这里我指定状态码为
|
||||
ResponseVO resultBean =new ResponseVO();
|
||||
resultBean.setCode(e.getCode());
|
||||
resultBean.setMsg(e.getError());
|
||||
return resultBean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validator 参数校验异常处理
|
||||
*
|
||||
* @param ex
|
||||
* @return
|
||||
*/
|
||||
@ExceptionHandler(value = BindException.class)
|
||||
@ResponseBody
|
||||
public Object handleException2(BindException ex) {
|
||||
FieldError err = ex.getFieldError();
|
||||
String message = "参数{".concat(err.getField()).concat("}").concat(err.getDefaultMessage());
|
||||
ResponseVO resultBean =new ResponseVO();
|
||||
resultBean.setCode(BaseErrorCode.PARAMETER_ERROR.getCode());
|
||||
resultBean.setMsg(message);
|
||||
return resultBean;
|
||||
|
||||
|
||||
}
|
||||
|
||||
//json格式
|
||||
@ExceptionHandler(value = MethodArgumentNotValidException.class)
|
||||
@ResponseBody
|
||||
public Object handleException1(MethodArgumentNotValidException ex) {
|
||||
StringBuilder errorMsg = new StringBuilder();
|
||||
BindingResult re = ex.getBindingResult();
|
||||
for (ObjectError error : re.getAllErrors()) {
|
||||
errorMsg.append(error.getDefaultMessage()).append(",");
|
||||
}
|
||||
errorMsg.delete(errorMsg.length() - 1, errorMsg.length());
|
||||
|
||||
ResponseVO resultBean =new ResponseVO();
|
||||
resultBean.setCode(BaseErrorCode.PARAMETER_ERROR.getCode());
|
||||
resultBean.setMsg(BaseErrorCode.PARAMETER_ERROR.getError() + " : " + errorMsg.toString());
|
||||
return resultBean;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.app.model.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: lld
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Data
|
||||
public class ImUserDataDto {
|
||||
|
||||
// 用户id
|
||||
private String userId;
|
||||
|
||||
// 用户名称
|
||||
private String nickName;
|
||||
|
||||
private String password;
|
||||
|
||||
// 头像
|
||||
private String photo;
|
||||
|
||||
// 性别
|
||||
private Integer userSex;
|
||||
|
||||
// 个性签名
|
||||
private String selfSignature;
|
||||
|
||||
// 加好友验证类型(Friend_AllowType) 1需要验证
|
||||
private Integer friendAllowType;
|
||||
|
||||
// 管理员禁止用户添加加好友:0 未禁用 1 已禁用
|
||||
private Integer disableAddFriend;
|
||||
|
||||
// 禁用标识(0 未禁用 1 已禁用)
|
||||
private Integer forbiddenFlag;
|
||||
|
||||
// 禁言标识
|
||||
private Integer silentFlag;
|
||||
/**
|
||||
* 用户类型 1普通用户 2客服 3机器人 100后台管理员
|
||||
*/
|
||||
private Integer userType;
|
||||
|
||||
private Integer appId;
|
||||
|
||||
private Integer delFlag;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.app.model.proto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
@Data
|
||||
public class GetUserInfoProto {
|
||||
|
||||
private List<String> userIds;
|
||||
|
||||
private List<String> standardField;
|
||||
|
||||
private List<String> customField;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.app.model.proto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
@Data
|
||||
public class ImportUserProto {
|
||||
|
||||
private List<UserData> userData;
|
||||
|
||||
@Data
|
||||
public static class UserData{
|
||||
// 用户id
|
||||
private String userId;
|
||||
|
||||
// 用户名称
|
||||
private String nickName;
|
||||
|
||||
private String password;
|
||||
|
||||
// 头像
|
||||
private String photo;
|
||||
|
||||
// 性别
|
||||
private Integer userSex;
|
||||
|
||||
// 个性签名
|
||||
private String selfSignature;
|
||||
|
||||
// 加好友验证类型(Friend_AllowType) 1需要验证
|
||||
private Integer friendAllowType;
|
||||
|
||||
// 管理员禁止用户添加加好友:0 未禁用 1 已禁用
|
||||
private Integer disableAddFriend;
|
||||
|
||||
// 禁用标识(0 未禁用 1 已禁用)
|
||||
private Integer forbiddenFlag;
|
||||
|
||||
// 禁言标识
|
||||
private Integer silentFlag;
|
||||
/**
|
||||
* 用户类型 1普通用户 2客服 3机器人
|
||||
*/
|
||||
private Integer userType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.app.model.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
@Data
|
||||
public class LoginReq {
|
||||
|
||||
@NotBlank(message = "用户名不能为空")
|
||||
private String userName;
|
||||
|
||||
@NotBlank(message = "密码不能为空")
|
||||
private String password;
|
||||
|
||||
@NotNull(message = "请选择登录方式")
|
||||
//登录方式 1用户名+密码 2手机号+验证码
|
||||
private Integer loginType;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.app.model.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
@Data
|
||||
public class RegisterReq {
|
||||
|
||||
private String userName;
|
||||
|
||||
@NotBlank(message = "密码不能为空")
|
||||
private String password;
|
||||
|
||||
@NotNull(message = "请选择注册方式")
|
||||
//注册方式 1手机号注册 2用户名
|
||||
private Integer registerType;
|
||||
|
||||
private String proto;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.app.model.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
@Data
|
||||
public class SearchUserReq {
|
||||
|
||||
@NotBlank(message = "关键字不能为空")
|
||||
private String keyWord;
|
||||
|
||||
@NotNull(message = "搜索方式不能为空")
|
||||
private Integer searchType;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.app.model.resp;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
@Data
|
||||
public class ImportUserResp {
|
||||
private Set<String> successId;
|
||||
|
||||
private Set<String> errorId;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.app.model.resp;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
@Data
|
||||
public class LoginResp {
|
||||
|
||||
//im的token
|
||||
private String imUserSign;
|
||||
|
||||
//自己的token
|
||||
private String userSign;
|
||||
|
||||
private String userId;
|
||||
|
||||
private Integer appId;
|
||||
|
||||
}
|
||||
104
hs-im-app-server/src/main/java/org/app/service/ImService.java
Normal file
104
hs-im-app-server/src/main/java/org/app/service/ImService.java
Normal file
@@ -0,0 +1,104 @@
|
||||
package org.app.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.app.common.ResponseVO;
|
||||
import org.app.config.AppConfig;
|
||||
import org.app.dao.User;
|
||||
import org.app.model.dto.ImUserDataDto;
|
||||
import org.app.model.proto.GetUserInfoProto;
|
||||
import org.app.model.proto.ImportUserProto;
|
||||
import org.app.model.resp.ImportUserResp;
|
||||
import org.app.utils.HttpRequestUtils;
|
||||
import org.app.utils.SigAPI;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
@Service
|
||||
public class ImService implements CommandLineRunner {
|
||||
|
||||
@Autowired
|
||||
HttpRequestUtils httpRequestUtils;
|
||||
|
||||
@Autowired
|
||||
AppConfig appConfig;
|
||||
|
||||
private SigAPI sigAPI;
|
||||
|
||||
public volatile static Map<String, Object> parameter;
|
||||
|
||||
public volatile static Object lock = new Object();
|
||||
|
||||
private String getUrl(String uri) {
|
||||
return appConfig.getImUrl() + "/" + appConfig.getImVersion() + uri;
|
||||
}
|
||||
|
||||
private Map<String, Object> getParamter() {
|
||||
if (parameter == null) {
|
||||
synchronized (lock) {
|
||||
if(parameter == null){
|
||||
parameter = new ConcurrentHashMap<>();
|
||||
parameter.put("appId",appConfig.getAppId());
|
||||
parameter.put("userSign",sigAPI.genUserSig(appConfig.getAdminId(),500000));
|
||||
parameter.put("identifier",appConfig.getAdminId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return parameter;
|
||||
}
|
||||
|
||||
public ResponseVO<ImportUserResp> importUser(List<User> users) {
|
||||
|
||||
ImportUserProto proto = new ImportUserProto();
|
||||
List<ImportUserProto.UserData> userData = new ArrayList<>();
|
||||
users.forEach(e -> {
|
||||
ImportUserProto.UserData u = new ImportUserProto.UserData();
|
||||
u.setUserId(e.getUserId().toString());
|
||||
u.setUserType(1);
|
||||
userData.add(u);
|
||||
});
|
||||
|
||||
String uri = "/user/importUser";
|
||||
try {
|
||||
proto.setUserData(userData);
|
||||
ResponseVO responseVO = httpRequestUtils.doPost(getUrl(uri), ResponseVO.class, getParamter(), null, JSONObject.toJSONString(proto), "");
|
||||
return responseVO;
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return ResponseVO.errorResponse();
|
||||
}
|
||||
|
||||
|
||||
public ResponseVO<ImUserDataDto> getUserInfo(List<String> users) {
|
||||
|
||||
GetUserInfoProto proto = new GetUserInfoProto();
|
||||
proto.setUserIds(users);
|
||||
|
||||
String uri = "/user/data/getUserInfo";
|
||||
try {
|
||||
// proto.setUserData(userData);
|
||||
ResponseVO responseVO = httpRequestUtils.doPost(getUrl(uri), ResponseVO.class, getParamter(), null, JSONObject.toJSONString(proto), "");
|
||||
return responseVO;
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
return ResponseVO.errorResponse();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
sigAPI = new SigAPI(appConfig.getAppId(),appConfig.getPrivateKey());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.app.service;
|
||||
|
||||
|
||||
import org.app.common.ResponseVO;
|
||||
import org.app.model.req.LoginReq;
|
||||
import org.app.model.req.RegisterReq;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
public interface LoginService {
|
||||
|
||||
public ResponseVO login(LoginReq req);
|
||||
|
||||
public ResponseVO register(RegisterReq req);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.app.service;
|
||||
|
||||
|
||||
import org.app.common.ResponseVO;
|
||||
import org.app.dao.User;
|
||||
import org.app.model.req.RegisterReq;
|
||||
import org.app.model.req.SearchUserReq;
|
||||
|
||||
public interface UserService {
|
||||
|
||||
public ResponseVO<User> getUserByUserNameAndPassword(String userName, String password);
|
||||
|
||||
public ResponseVO<User> getUserByMobile(String mobile);
|
||||
|
||||
public ResponseVO<User> getUserByUserName(String userName);
|
||||
|
||||
public ResponseVO<User> getUserById(Integer userId);
|
||||
|
||||
public ResponseVO<User> registerUser(RegisterReq req);
|
||||
|
||||
public ResponseVO searchUser(SearchUserReq req);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package org.app.service.impl;
|
||||
|
||||
import org.app.common.ResponseVO;
|
||||
import org.app.config.AppConfig;
|
||||
import org.app.dao.User;
|
||||
import org.app.enums.ErrorCode;
|
||||
import org.app.enums.LoginTypeEnum;
|
||||
import org.app.enums.RegisterTypeEnum;
|
||||
import org.app.model.req.LoginReq;
|
||||
import org.app.model.req.RegisterReq;
|
||||
import org.app.model.resp.LoginResp;
|
||||
import org.app.service.LoginService;
|
||||
import org.app.service.UserService;
|
||||
import org.app.utils.SigAPI;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
@Service
|
||||
public class LoginServiceImpl implements LoginService {
|
||||
|
||||
@Autowired
|
||||
UserService userService;
|
||||
|
||||
@Autowired
|
||||
AppConfig appConfig;
|
||||
|
||||
/**
|
||||
* @param [req]
|
||||
* @return com.lld.app.common.ResponseVO
|
||||
* @description 登录服务,需返回im userSign,和app的userSign
|
||||
* @author chackylee
|
||||
*/
|
||||
@Override
|
||||
public ResponseVO login(LoginReq req) {
|
||||
|
||||
LoginResp loginResp = new LoginResp();
|
||||
|
||||
if (LoginTypeEnum.USERNAME_PASSWORD.getCode() == req.getLoginType()) {
|
||||
ResponseVO<User> userResp = userService.getUserByUserNameAndPassword(req.getUserName(), req.getPassword());
|
||||
if (userResp.isOk()) {
|
||||
User user = userResp.getData();
|
||||
SigAPI SigAPI = new SigAPI(appConfig.getAppId(),
|
||||
appConfig.getPrivateKey());
|
||||
String s = SigAPI.genUserSig(user.getUserId(),
|
||||
500000);
|
||||
loginResp.setImUserSign(s);
|
||||
loginResp.setUserSign("asdasdsd");
|
||||
loginResp.setUserId(user.getUserId());
|
||||
} else if (userResp.getCode() == ErrorCode.USER_NOT_EXIST.getCode()) {
|
||||
return ResponseVO.errorResponse(ErrorCode.USERNAME_OR_PASSWORD_ERROR);
|
||||
} else {
|
||||
return userResp;
|
||||
}
|
||||
|
||||
} else if (LoginTypeEnum.SMS_CODE.getCode() == req.getLoginType()) {
|
||||
String key = "lld";
|
||||
}
|
||||
|
||||
loginResp.setAppId(appConfig.getAppId());
|
||||
return ResponseVO.successResponse(loginResp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 注册我们的服务并向im导入用户
|
||||
* @author chackylee
|
||||
* @param [req]
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public ResponseVO register(RegisterReq req) {
|
||||
if(RegisterTypeEnum.USERNAME.getCode() == req.getRegisterType()){
|
||||
ResponseVO<User> userByUserName = userService.getUserByUserName(req.getUserName());
|
||||
if(userByUserName.isOk()){
|
||||
return ResponseVO.errorResponse(ErrorCode.REGISTER_ERROR);
|
||||
}
|
||||
ResponseVO<User> userResponseVO = userService.registerUser(req);
|
||||
return userResponseVO;
|
||||
}
|
||||
return ResponseVO.successResponse();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package org.app.service.impl;
|
||||
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.app.common.ResponseVO;
|
||||
import org.app.dao.User;
|
||||
import org.app.dao.mapper.UserMapper;
|
||||
import org.app.enums.ErrorCode;
|
||||
import org.app.exception.ApplicationException;
|
||||
import org.app.model.dto.ImUserDataDto;
|
||||
import org.app.model.req.RegisterReq;
|
||||
import org.app.model.req.SearchUserReq;
|
||||
import org.app.model.resp.ImportUserResp;
|
||||
import org.app.service.ImService;
|
||||
import org.app.service.UserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
@Service
|
||||
public class UserServiceImpl implements UserService {
|
||||
|
||||
@Autowired
|
||||
UserMapper userMapper;
|
||||
|
||||
@Autowired
|
||||
ImService imService;
|
||||
|
||||
/**
|
||||
* @param [userName, password]
|
||||
* @return com.lld.app.common.ResponseVO
|
||||
* @description 根据用户名和密码获取用户
|
||||
* @author chackylee
|
||||
*/
|
||||
@Override
|
||||
public ResponseVO getUserByUserNameAndPassword(String userName, String password) {
|
||||
|
||||
QueryWrapper<User> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("user_name", userName);
|
||||
wrapper.eq("password", password);
|
||||
User user = userMapper.selectOne(wrapper);
|
||||
|
||||
if (user == null) {
|
||||
return ResponseVO.errorResponse(ErrorCode.USER_NOT_EXIST);
|
||||
}
|
||||
|
||||
return ResponseVO.successResponse(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [mobile]
|
||||
* @return com.lld.app.common.ResponseVO
|
||||
* @description 根据手机号获取用户
|
||||
* @author chackylee
|
||||
*/
|
||||
@Override
|
||||
public ResponseVO getUserByMobile(String mobile) {
|
||||
QueryWrapper<User> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("mobile", mobile);
|
||||
User user = userMapper.selectOne(wrapper);
|
||||
|
||||
if (user == null) {
|
||||
return ResponseVO.errorResponse(ErrorCode.USER_NOT_EXIST);
|
||||
}
|
||||
return ResponseVO.successResponse(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseVO<User> getUserByUserName(String userName) {
|
||||
QueryWrapper<User> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("user_name", userName);
|
||||
User user = userMapper.selectOne(wrapper);
|
||||
|
||||
if (user == null) {
|
||||
return ResponseVO.errorResponse(ErrorCode.USER_NOT_EXIST);
|
||||
}
|
||||
return ResponseVO.successResponse(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [userId]
|
||||
* @return com.lld.app.common.ResponseVO
|
||||
* @description 根据用户id获取用户
|
||||
* @author chackylee
|
||||
*/
|
||||
@Override
|
||||
public ResponseVO getUserById(Integer userId) {
|
||||
|
||||
User user = userMapper.selectById(userId);
|
||||
if (user == null) {
|
||||
return ResponseVO.errorResponse(ErrorCode.USER_NOT_EXIST);
|
||||
}
|
||||
return ResponseVO.successResponse(user);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public ResponseVO<User> registerUser(RegisterReq req) {
|
||||
|
||||
User user = new User();
|
||||
user.setCreateTime(System.currentTimeMillis());
|
||||
// user.setMobile(req.getUserName());
|
||||
user.setPassword(req.getPassword());
|
||||
user.setUserName(req.getUserName());
|
||||
user.setUserId(req.getUserName());
|
||||
userMapper.insert(user);
|
||||
|
||||
ArrayList<User> users = new ArrayList<>();
|
||||
users.add(user);
|
||||
ResponseVO responseVO = imService.importUser(users);
|
||||
if(responseVO.isOk()){
|
||||
Object data = responseVO.getData();
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
ImportUserResp importUserResp = objectMapper.convertValue(data, ImportUserResp.class);
|
||||
|
||||
Set<String> successId = importUserResp.getSuccessId();
|
||||
if(successId.contains(user.getUserId().toString())){
|
||||
return ResponseVO.successResponse(user);
|
||||
}else {
|
||||
throw new ApplicationException(ErrorCode.REGISTER_ERROR);
|
||||
}
|
||||
}else{
|
||||
throw new ApplicationException(responseVO.getCode(),responseVO.getMsg());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseVO searchUser(SearchUserReq req) {
|
||||
|
||||
List<String> userIds = userMapper.searchUser(req);
|
||||
|
||||
//手机号搜索
|
||||
// if(req.getSearchType() == 1){
|
||||
// userIds = userMapper.searchUser(req);
|
||||
// }else if(){
|
||||
//
|
||||
// }
|
||||
ResponseVO<ImUserDataDto> userInfo = imService.getUserInfo(userIds);
|
||||
|
||||
return userInfo;
|
||||
}
|
||||
}
|
||||
90
hs-im-app-server/src/main/java/org/app/utils/Base64URL.java
Normal file
90
hs-im-app-server/src/main/java/org/app/utils/Base64URL.java
Normal file
@@ -0,0 +1,90 @@
|
||||
package org.app.utils;
|
||||
import sun.misc.BASE64Decoder;
|
||||
import sun.misc.BASE64Encoder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: lld
|
||||
* @version: 1.0
|
||||
*/
|
||||
|
||||
|
||||
public class Base64URL {
|
||||
public static byte[] base64EncodeUrl(byte[] input) {
|
||||
byte[] base64 = new BASE64Encoder().encode(input).getBytes();
|
||||
for (int i = 0; i < base64.length; ++i)
|
||||
switch (base64[i]) {
|
||||
case '+':
|
||||
base64[i] = '*';
|
||||
break;
|
||||
case '/':
|
||||
base64[i] = '-';
|
||||
break;
|
||||
case '=':
|
||||
base64[i] = '_';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return base64;
|
||||
}
|
||||
|
||||
public static byte[] base64EncodeUrlNotReplace(byte[] input) {
|
||||
byte[] base64 = new BASE64Encoder().encode(input).getBytes(Charset.forName("UTF-8"));
|
||||
for (int i = 0; i < base64.length; ++i)
|
||||
switch (base64[i]) {
|
||||
case '+':
|
||||
base64[i] = '*';
|
||||
break;
|
||||
case '/':
|
||||
base64[i] = '-';
|
||||
break;
|
||||
case '=':
|
||||
base64[i] = '_';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return base64;
|
||||
}
|
||||
|
||||
public static byte[] base64DecodeUrlNotReplace(byte[] input) throws IOException {
|
||||
for (int i = 0; i < input.length; ++i)
|
||||
switch (input[i]) {
|
||||
case '*':
|
||||
input[i] = '+';
|
||||
break;
|
||||
case '-':
|
||||
input[i] = '/';
|
||||
break;
|
||||
case '_':
|
||||
input[i] = '=';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return new BASE64Decoder().decodeBuffer(new String(input,"UTF-8"));
|
||||
}
|
||||
|
||||
public static byte[] base64DecodeUrl(byte[] input) throws IOException {
|
||||
byte[] base64 = input.clone();
|
||||
for (int i = 0; i < base64.length; ++i)
|
||||
switch (base64[i]) {
|
||||
case '*':
|
||||
base64[i] = '+';
|
||||
break;
|
||||
case '-':
|
||||
base64[i] = '/';
|
||||
break;
|
||||
case '_':
|
||||
base64[i] = '=';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return new BASE64Decoder().decodeBuffer(base64.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
package org.app.utils;
|
||||
|
||||
import org.app.config.GlobalHttpClientConfig;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
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.util.EntityUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author: Chackylee
|
||||
* @description:
|
||||
**/
|
||||
@Component
|
||||
public class HttpRequestUtils {
|
||||
|
||||
@Autowired
|
||||
private CloseableHttpClient httpClient;
|
||||
|
||||
@Autowired
|
||||
private RequestConfig requestConfig;
|
||||
|
||||
@Autowired
|
||||
GlobalHttpClientConfig httpClientConfig;
|
||||
|
||||
public String doGet(String url, Map<String, Object> params, String charset) throws Exception {
|
||||
return doGet(url,params,null,charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过给的url地址,获取服务器数据
|
||||
*
|
||||
* @param url 服务器地址
|
||||
* @param params 封装用户参数
|
||||
* @param charset 设定字符编码
|
||||
* @return
|
||||
*/
|
||||
public String doGet(String url, Map<String, Object> params, Map<String, Object> header, String charset) throws Exception {
|
||||
|
||||
if (StringUtils.isEmpty(charset)) {
|
||||
charset = "utf-8";
|
||||
}
|
||||
URIBuilder uriBuilder = new URIBuilder(url);
|
||||
// 判断是否有参数
|
||||
if (params != null) {
|
||||
// 遍历map,拼接请求参数
|
||||
for (Map.Entry<String, Object> entry : params.entrySet()) {
|
||||
uriBuilder.setParameter(entry.getKey(), entry.getValue().toString());
|
||||
}
|
||||
}
|
||||
// 声明 http get 请求
|
||||
HttpGet httpGet = new HttpGet(uriBuilder.build());
|
||||
httpGet.setConfig(requestConfig);
|
||||
|
||||
if (header != null) {
|
||||
// 遍历map,拼接header参数
|
||||
for (Map.Entry<String, Object> entry : header.entrySet()) {
|
||||
httpGet.addHeader(entry.getKey(),entry.getValue().toString());
|
||||
}
|
||||
}
|
||||
|
||||
String result = "";
|
||||
try {
|
||||
// 发起请求
|
||||
CloseableHttpResponse response = httpClient.execute(httpGet);
|
||||
// 判断状态码是否为200
|
||||
if (response.getStatusLine().getStatusCode() == 200) {
|
||||
// 返回响应体的内容
|
||||
result = EntityUtils.toString(response.getEntity(), charset);
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* GET请求, 含URL 参数
|
||||
*
|
||||
* @param url
|
||||
* @param params
|
||||
* @return 如果状态码为200,则返回body,如果不为200,则返回null
|
||||
* @throws Exception
|
||||
*/
|
||||
public String doGet(String url, Map<String, Object> params) throws Exception {
|
||||
return doGet(url, params, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET 请求,不含URL参数
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public String doGet(String url) throws Exception {
|
||||
return doGet(url, null, null);
|
||||
}
|
||||
|
||||
public String doPost(String url, Map<String, Object> params, String jsonBody, String charset) throws Exception {
|
||||
return doPost(url,params,null,jsonBody,charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 带参数的post请求
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public String doPost(String url, Map<String, Object> params, Map<String, Object> header, String jsonBody, String charset) throws Exception {
|
||||
|
||||
if (StringUtils.isEmpty(charset)) {
|
||||
charset = "utf-8";
|
||||
}
|
||||
URIBuilder uriBuilder = new URIBuilder(url);
|
||||
// 判断是否有参数
|
||||
if (params != null) {
|
||||
// 遍历map,拼接请求参数
|
||||
for (Map.Entry<String, Object> entry : params.entrySet()) {
|
||||
uriBuilder.setParameter(entry.getKey(), entry.getValue().toString());
|
||||
}
|
||||
}
|
||||
|
||||
// 声明httpPost请求
|
||||
HttpPost httpPost = new HttpPost(uriBuilder.build());
|
||||
// 加入配置信息
|
||||
httpPost.setConfig(requestConfig);
|
||||
|
||||
// 判断map是否为空,不为空则进行遍历,封装from表单对象
|
||||
if (StringUtils.isNotEmpty(jsonBody)) {
|
||||
StringEntity s = new StringEntity(jsonBody, charset);
|
||||
s.setContentEncoding(charset);
|
||||
s.setContentType("application/json");
|
||||
|
||||
// 把json body放到post里
|
||||
httpPost.setEntity(s);
|
||||
}
|
||||
|
||||
if (header != null) {
|
||||
// 遍历map,拼接header参数
|
||||
for (Map.Entry<String, Object> entry : header.entrySet()) {
|
||||
httpPost.addHeader(entry.getKey(),entry.getValue().toString());
|
||||
}
|
||||
}
|
||||
|
||||
String result = "";
|
||||
// CloseableHttpClient httpClient = HttpClients.createDefault(); // 单个
|
||||
CloseableHttpResponse response = null;
|
||||
try {
|
||||
// 发起请求
|
||||
response = httpClient.execute(httpPost);
|
||||
// 判断状态码是否为200
|
||||
if (response.getStatusLine().getStatusCode() == 200) {
|
||||
// 返回响应体的内容
|
||||
result = EntityUtils.toString(response.getEntity(), charset);
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 不带参数post请求
|
||||
* @param url
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public String doPost(String url) throws Exception {
|
||||
return doPost(url, null,null,null);
|
||||
}
|
||||
|
||||
/**
|
||||
* get 方法调用的通用方式
|
||||
* @param url
|
||||
* @param tClass
|
||||
* @param map
|
||||
* @param charSet
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public <T> T doGet(String url, Class<T> tClass, Map<String, Object> map, String charSet) throws Exception {
|
||||
|
||||
String result = doGet(url, map, charSet);
|
||||
if (StringUtils.isNotEmpty(result))
|
||||
return JSON.parseObject(result, tClass);
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* get 方法调用的通用方式
|
||||
* @param url
|
||||
* @param tClass
|
||||
* @param map
|
||||
* @param charSet
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public <T> T doGet(String url, Class<T> tClass, Map<String, Object> map, Map<String, Object> header, String charSet) throws Exception {
|
||||
|
||||
String result = doGet(url, map, header, charSet);
|
||||
if (StringUtils.isNotEmpty(result))
|
||||
return JSON.parseObject(result, tClass);
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* post 方法调用的通用方式
|
||||
* @param url
|
||||
* @param tClass
|
||||
* @param map
|
||||
* @param jsonBody
|
||||
* @param charSet
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public <T> T doPost(String url, Class<T> tClass, Map<String, Object> map, String jsonBody, String charSet) throws Exception {
|
||||
|
||||
String result = doPost(url, map,jsonBody,charSet);
|
||||
if (StringUtils.isNotEmpty(result))
|
||||
return JSON.parseObject(result, tClass);
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
public <T> T doPost(String url, Class<T> tClass, Map<String, Object> map, Map<String, Object> header, String jsonBody, String charSet) throws Exception {
|
||||
|
||||
String result = doPost(url, map, header,jsonBody,charSet);
|
||||
if (StringUtils.isNotEmpty(result))
|
||||
return JSON.parseObject(result, tClass);
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* post 方法调用的通用方式
|
||||
* @param url
|
||||
* @param map
|
||||
* @param jsonBody
|
||||
* @param charSet
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public String doPostString(String url, Map<String, Object> map, String jsonBody, String charSet) throws Exception {
|
||||
return doPost(url, map,jsonBody,charSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* post 方法调用的通用方式
|
||||
* @param url
|
||||
* @param map
|
||||
* @param jsonBody
|
||||
* @param charSet
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public String doPostString(String url, Map<String, Object> map, Map<String, Object> header, String jsonBody, String charSet) throws Exception {
|
||||
return doPost(url, map, header, jsonBody,charSet);
|
||||
}
|
||||
|
||||
}
|
||||
195
hs-im-app-server/src/main/java/org/app/utils/SigAPI.java
Normal file
195
hs-im-app-server/src/main/java/org/app/utils/SigAPI.java
Normal file
@@ -0,0 +1,195 @@
|
||||
package org.app.utils;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.app.utils.Base64URL;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.Inflater;
|
||||
|
||||
|
||||
/**
|
||||
* @description: app用户 后台管理员
|
||||
*
|
||||
* 10000 xxx 10001 bbbb
|
||||
* @author: lld
|
||||
* @version: 1.0
|
||||
*/
|
||||
public class SigAPI {
|
||||
final private long appId;
|
||||
final private String key;
|
||||
|
||||
public SigAPI(long appId, String key) {
|
||||
this.appId = appId;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
SigAPI asd = new SigAPI(10000, "123456");
|
||||
String sign = asd.genUserSig("lld", 100000000);
|
||||
// Thread.sleep(2000L);
|
||||
JSONObject jsonObject = decodeUserSig(sign);
|
||||
System.out.println("sign:" + sign);
|
||||
System.out.println("decoder:" + jsonObject.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 解密方法
|
||||
* @param
|
||||
* @return com.alibaba.fastjson.JSONObject
|
||||
* @author lld
|
||||
*/
|
||||
public static JSONObject decodeUserSig(String userSig) {
|
||||
JSONObject sigDoc = new JSONObject(true);
|
||||
try {
|
||||
byte[] decodeUrlByte = Base64URL.base64DecodeUrlNotReplace(userSig.getBytes());
|
||||
byte[] decompressByte = decompress(decodeUrlByte);
|
||||
String decodeText = new String(decompressByte, "UTF-8");
|
||||
|
||||
if (StringUtils.isNotBlank(decodeText)) {
|
||||
sigDoc = JSONObject.parseObject(decodeText);
|
||||
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
return sigDoc;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解压缩
|
||||
*
|
||||
* @param data 待压缩的数据
|
||||
* @return byte[] 解压缩后的数据
|
||||
*/
|
||||
public static byte[] decompress(byte[] data) {
|
||||
byte[] output = new byte[0];
|
||||
|
||||
Inflater decompresser = new Inflater();
|
||||
decompresser.reset();
|
||||
decompresser.setInput(data);
|
||||
|
||||
ByteArrayOutputStream o = new ByteArrayOutputStream(data.length);
|
||||
try {
|
||||
byte[] buf = new byte[1024];
|
||||
while (!decompresser.finished()) {
|
||||
int i = decompresser.inflate(buf);
|
||||
o.write(buf, 0, i);
|
||||
}
|
||||
output = o.toByteArray();
|
||||
} catch (Exception e) {
|
||||
output = data;
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
o.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
decompresser.end();
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 【功能说明】用于签发 IM 服务中必须要使用的 UserSig 鉴权票据
|
||||
* <p>
|
||||
* 【参数说明】
|
||||
*/
|
||||
public String genUserSig(String userid, long expire) {
|
||||
return genUserSig(userid, expire, null);
|
||||
}
|
||||
|
||||
|
||||
private String hmacsha256(String identifier, long currTime, long expire, String base64Userbuf) {
|
||||
String contentToBeSigned = "TLS.identifier:" + identifier + "\n"
|
||||
+ "TLS.appId:" + appId + "\n"
|
||||
+ "TLS.expireTime:" + currTime + "\n"
|
||||
+ "TLS.expire:" + expire + "\n";
|
||||
if (null != base64Userbuf) {
|
||||
contentToBeSigned += "TLS.userbuf:" + base64Userbuf + "\n";
|
||||
}
|
||||
try {
|
||||
byte[] byteKey = key.getBytes(StandardCharsets.UTF_8);
|
||||
Mac hmac = Mac.getInstance("HmacSHA256");
|
||||
SecretKeySpec keySpec = new SecretKeySpec(byteKey, "HmacSHA256");
|
||||
hmac.init(keySpec);
|
||||
byte[] byteSig = hmac.doFinal(contentToBeSigned.getBytes(StandardCharsets.UTF_8));
|
||||
return (Base64.getEncoder().encodeToString(byteSig)).replaceAll("\\s*", "");
|
||||
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private String genUserSig(String userid, long expire, byte[] userbuf) {
|
||||
|
||||
long currTime = System.currentTimeMillis() / 1000;
|
||||
|
||||
JSONObject sigDoc = new JSONObject();
|
||||
sigDoc.put("TLS.identifier", userid);
|
||||
sigDoc.put("TLS.appId", appId);
|
||||
sigDoc.put("TLS.expire", expire);
|
||||
sigDoc.put("TLS.expireTime", currTime);
|
||||
|
||||
String base64UserBuf = null;
|
||||
if (null != userbuf) {
|
||||
base64UserBuf = Base64.getEncoder().encodeToString(userbuf).replaceAll("\\s*", "");
|
||||
sigDoc.put("TLS.userbuf", base64UserBuf);
|
||||
}
|
||||
String sig = hmacsha256(userid, currTime, expire, base64UserBuf);
|
||||
if (sig.length() == 0) {
|
||||
return "";
|
||||
}
|
||||
sigDoc.put("TLS.sig", sig);
|
||||
Deflater compressor = new Deflater();
|
||||
compressor.setInput(sigDoc.toString().getBytes(StandardCharsets.UTF_8));
|
||||
compressor.finish();
|
||||
byte[] compressedBytes = new byte[2048];
|
||||
int compressedBytesLength = compressor.deflate(compressedBytes);
|
||||
compressor.end();
|
||||
return (new String(Base64URL.base64EncodeUrl(Arrays.copyOfRange(compressedBytes,
|
||||
0, compressedBytesLength)))).replaceAll("\\s*", "");
|
||||
}
|
||||
|
||||
public String genUserSig(String userid, long expire, long time,byte [] userbuf) {
|
||||
|
||||
JSONObject sigDoc = new JSONObject();
|
||||
sigDoc.put("TLS.identifier", userid);
|
||||
sigDoc.put("TLS.appId", appId);
|
||||
sigDoc.put("TLS.expire", expire);
|
||||
sigDoc.put("TLS.expireTime", time);
|
||||
|
||||
String base64UserBuf = null;
|
||||
if (null != userbuf) {
|
||||
base64UserBuf = Base64.getEncoder().encodeToString(userbuf).replaceAll("\\s*", "");
|
||||
sigDoc.put("TLS.userbuf", base64UserBuf);
|
||||
}
|
||||
String sig = hmacsha256(userid, time, expire, base64UserBuf);
|
||||
if (sig.length() == 0) {
|
||||
return "";
|
||||
}
|
||||
sigDoc.put("TLS.sig", sig);
|
||||
Deflater compressor = new Deflater();
|
||||
compressor.setInput(sigDoc.toString().getBytes(StandardCharsets.UTF_8));
|
||||
compressor.finish();
|
||||
byte[] compressedBytes = new byte[2048];
|
||||
int compressedBytesLength = compressor.deflate(compressedBytes);
|
||||
compressor.end();
|
||||
return (new String(Base64URL.base64EncodeUrl(Arrays.copyOfRange(compressedBytes,
|
||||
0, compressedBytesLength)))).replaceAll("\\s*", "");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user