静态资源功能、散户端登录问题修复、订单业务功能开发v2、swagger枚举转换器功能

wxpay
LI-CCONG\李聪聪 8 months ago
parent fb65771248
commit cc1877fd39

@ -6,26 +6,36 @@ import cc.yunxi.common.exception.DbException;
import cc.yunxi.common.domain.CommonResult;
import cc.yunxi.common.utils.WebUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
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 org.springframework.web.util.NestedServletException;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Path;
import java.net.BindException;
import java.util.stream.Collectors;
import java.util.Iterator;
import java.util.List;
@RestControllerAdvice
@Slf4j
public class CommonExceptionAdvice {
@ResponseBody
@ExceptionHandler(DbException.class)
public Object handleDbException(DbException e) {
log.error("mysql数据库操作异常 -> ", e);
return processResponse(e);
}
@ResponseBody
@ExceptionHandler(CommonException.class)
public Object handleBadRequestException(CommonException e) {
log.error("自定义异常 -> {} , 异常原因:{} ",e.getClass().getName(), e.getMessage());
@ -33,15 +43,46 @@ public class CommonExceptionAdvice {
return processResponse(e);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
String msg = e.getBindingResult().getAllErrors()
.stream().map(ObjectError::getDefaultMessage)
.collect(Collectors.joining("|"));
log.error("请求参数校验异常 -> {}", msg);
/**
*
*/
@ResponseBody
@ExceptionHandler({org.springframework.validation.BindException.class, ConstraintViolationException.class, MethodArgumentNotValidException.class})
public Object handleException(Exception e, HttpServletRequest request) {
StringBuffer errorMsg = new StringBuffer();
if (!(e instanceof org.springframework.validation.BindException) && !(e instanceof MethodArgumentNotValidException)) {
for (ConstraintViolation cv : ((ConstraintViolationException) e).getConstraintViolations()) {
Iterator<Path.Node> it = cv.getPropertyPath().iterator();
Path.Node last = null;
while (it.hasNext()) {
last = it.next();
}
errorMsg.append(last != null ? last.getName() : "").append(":").append(cv.getMessageTemplate()).append(";");
// errorMsg.append(cv.getMessageTemplate()).append(";");
}
} else {
List<ObjectError> allErrors;
if (e instanceof org.springframework.validation.BindException) {
allErrors = ((org.springframework.validation.BindException) e).getAllErrors();
} else {
allErrors = ((MethodArgumentNotValidException) e).getBindingResult().getAllErrors();
}
// 拼接错误信息
for (ObjectError oe : allErrors) {
if (oe instanceof FieldError) {
errorMsg.append(((FieldError) oe).getField()).append(":").append(oe.getDefaultMessage()).append(";");
// errorMsg.append(oe.getDefaultMessage()).append(";");
} else {
errorMsg.append(oe.getObjectName()).append(":").append(oe.getDefaultMessage()).append(";");
}
}
}
log.error("请求参数校验异常 -> {}", errorMsg);
log.debug("", e);
return processResponse(new BadRequestException(msg));
return processResponse(new BadRequestException(errorMsg.toString()));
}
@ExceptionHandler(BindException.class)
public Object handleBindException(BindException e) {
log.error("请求参数绑定异常 ->BindException {}", e.getMessage());
@ -63,6 +104,9 @@ public class CommonExceptionAdvice {
}
private ResponseEntity<CommonResult<Void>> processResponse(CommonException e){
return ResponseEntity.status(e.getCode()).body(CommonResult.error(e));
return ResponseEntity.status(e.getCode())
.contentType(MediaType.APPLICATION_JSON)
.header("Content-Encoding", "UTF-8")
.body(CommonResult.error(e));
}
}

@ -1,7 +1,9 @@
package cc.yunxi.common.config;
import cc.yunxi.common.domain.LocalDateTimeDeserializer;
import cc.yunxi.common.domain.LocalDateTimeSerializer;
import cc.yunxi.common.domain.convert.EnumDeserializer;
import cc.yunxi.common.domain.convert.EnumSerializer;
import cc.yunxi.common.domain.convert.LocalDateTimeDeserializer;
import cc.yunxi.common.domain.convert.LocalDateTimeSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.extern.slf4j.Slf4j;
@ -29,9 +31,13 @@ public class JsonConfig {
jacksonObjectMapperBuilder
.serializerByType(Long.class, ToStringSerializer.instance)
.serializerByType(BigInteger.class, ToStringSerializer.instance);
// LocalDateTime -> Instant
// LocalDateTime <-> Instant / String
jacksonObjectMapperBuilder.serializerByType(LocalDateTime.class, LocalDateTimeSerializer.INSTANCE);
jacksonObjectMapperBuilder.deserializerByType(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE);
// String <-> Enum
// jacksonObjectMapperBuilder.serializerByType(Enum.class, EnumSerializer.INSTANCE);
// jacksonObjectMapperBuilder.deserializerByType(Enum.class, EnumDeserializer.INSTANCE);
};
}
}

@ -0,0 +1,186 @@
package cc.yunxi.common.config;
import cc.yunxi.common.enums.SwaggerDisplayEnum;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.classmate.ResolvedType;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils;
import springfox.documentation.builders.ModelPropertyBuilder;
import springfox.documentation.builders.OperationBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.service.AllowableListValues;
import springfox.documentation.service.ResolvedMethodParameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
import springfox.documentation.spi.service.ExpandedParameterBuilderPlugin;
import springfox.documentation.spi.service.OperationBuilderPlugin;
import springfox.documentation.spi.service.ParameterBuilderPlugin;
import springfox.documentation.spi.service.contexts.OperationContext;
import springfox.documentation.spi.service.contexts.ParameterContext;
import springfox.documentation.spi.service.contexts.ParameterExpansionContext;
import java.lang.reflect.Field;
import java.lang.reflect.Parameter;
import java.util.*;
import java.util.stream.Collectors;
/**
* Swagger
*/
@Configuration
@Slf4j
public class SwaggerEnumPlugin implements ModelPropertyBuilderPlugin, ParameterBuilderPlugin, OperationBuilderPlugin, ExpandedParameterBuilderPlugin {
private static final String DELIMITER = ",";
@Override
public void apply(ModelPropertyContext context) {
Optional<BeanPropertyDefinition> optional = context.getBeanPropertyDefinition();
if (!optional.isPresent()) {
return;
}
Class<?> fieldType = optional.get().getField().getRawType();
addDescForEnum(context, fieldType);
}
private void addDescForEnum(ModelPropertyContext context, Class<?> fieldType) {
if (Enum.class.isAssignableFrom(fieldType)) {
SwaggerDisplayEnum anno = AnnotationUtils.findAnnotation(fieldType, SwaggerDisplayEnum.class);
if (anno != null) {
Object[] enumConstants = fieldType.getEnumConstants();
List<String> displayValues = getDisplayValues(anno, enumConstants);
ModelPropertyBuilder builder = context.getBuilder();
Field descField = ReflectionUtils.findField(builder.getClass(), "description");
ReflectionUtils.makeAccessible(descField);
String joinText = (ReflectionUtils.getField(descField, builder) == null ? "" : (ReflectionUtils.getField(descField, builder) + ":"))
+ String.join(DELIMITER, displayValues);
// builder.description(joinText).type(context.getResolver().resolve(Integer.class));
builder.description(joinText).type(context.getResolver().resolve(String.class));
}
}
}
@Override
public void apply(OperationContext context) {
Map<String, List<String>> map = new HashMap<>();
List<ResolvedMethodParameter> parameters = context.getParameters();
parameters.forEach(parameter -> {
ResolvedType parameterType = parameter.getParameterType();
Class<?> clazz = parameterType.getErasedType();
if (Enum.class.isAssignableFrom(clazz)) {
SwaggerDisplayEnum annotation = AnnotationUtils.findAnnotation(clazz, SwaggerDisplayEnum.class);
if (annotation != null) {
Object[] enumConstants = clazz.getEnumConstants();
List<String> displayValues = getDisplayValues(annotation, enumConstants);
map.put(parameter.defaultName().orElse(""), displayValues);
OperationBuilder operationBuilder = context.operationBuilder();
Field parametersField = ReflectionUtils.findField(operationBuilder.getClass(), "parameters");
ReflectionUtils.makeAccessible(parametersField);
List<Parameter> list = (List<Parameter>) ReflectionUtils.getField(parametersField, operationBuilder);
map.forEach((k, v) -> {
for (Parameter currentParameter : list) {
if (StringUtils.equals(currentParameter.getName(), k)) {
Field description = ReflectionUtils.findField(currentParameter.getClass(), "description");
ReflectionUtils.makeAccessible(description);
Object field = ReflectionUtils.getField(description, currentParameter);
ReflectionUtils.setField(description, currentParameter, field + ":" + String.join(DELIMITER, v));
break;
}
}
});
}
}
});
}
@Override
public void apply(ParameterContext context) {
Class<?> type = context.resolvedMethodParameter().getParameterType().getErasedType();
ParameterBuilder parameterBuilder = context.parameterBuilder();
setAvailableValue(parameterBuilder, type);
}
private void setAvailableValue(ParameterBuilder parameterBuilder, Class<?> type) {
if (Enum.class.isAssignableFrom(type)) {
SwaggerDisplayEnum annotation = AnnotationUtils.findAnnotation(type, SwaggerDisplayEnum.class);
if (annotation != null) {
String code = annotation.code();
Object[] enumConstants = type.getEnumConstants();
List<String> displayValues = Arrays.stream(enumConstants).filter(Objects::nonNull).map(item -> {
Class<?> currentClass = item.getClass();
Field codeField = ReflectionUtils.findField(currentClass, code);
assert codeField != null;
ReflectionUtils.makeAccessible(codeField);
Object codeStr = ReflectionUtils.getField(codeField, item);
assert codeStr != null;
return codeStr.toString();
}).collect(Collectors.toList());
// 设置可用值
AllowableListValues values = new AllowableListValues(displayValues, "LIST");
parameterBuilder.allowableValues(values);
}
}
}
@Override
public void apply(ParameterExpansionContext context) {
Class<?> type = context.getFieldType().getErasedType();
ParameterBuilder parameterBuilder = context.getParameterBuilder();
if (Enum.class.isAssignableFrom(type)) {
setAvailableValue(parameterBuilder, type);
SwaggerDisplayEnum annotation = AnnotationUtils.findAnnotation(type, SwaggerDisplayEnum.class);
if (annotation != null) {
Object[] enumConstants = type.getEnumConstants();
List<String> displayValues = getDisplayValues(annotation, enumConstants);
Field descField = ReflectionUtils.findField(parameterBuilder.getClass(), "description");
ReflectionUtils.makeAccessible(descField);
String joinText = (ReflectionUtils.getField(descField, parameterBuilder) == null ? "" : (ReflectionUtils.getField(descField, parameterBuilder) + ":"))
+ String.join(DELIMITER, displayValues);
parameterBuilder.description(joinText);
}
}
}
private List<String> getDisplayValues(SwaggerDisplayEnum annotation, Object[] enumConstants) {
if (annotation == null) {
return new ArrayList<>();
}
String code = annotation.code();
String desc = annotation.desc();
return Arrays.stream(enumConstants).filter(Objects::nonNull).map(
item -> {
Class<?> currentClass = item.getClass();
Field codeField = ReflectionUtils.findField(currentClass, code);
assert codeField != null;
ReflectionUtils.makeAccessible(codeField);
Object codeStr = ReflectionUtils.getField(codeField, item);
Field descField = ReflectionUtils.findField(currentClass, desc);
assert descField != null;
ReflectionUtils.makeAccessible(descField);
Object descStr = ReflectionUtils.getField(descField, item);
return codeStr + "、" + descStr;
}
).collect(Collectors.toList());
}
@Override
public boolean supports(DocumentationType documentationType) {
return true;
}
}

@ -1,6 +1,7 @@
package cc.yunxi.common.domain;
import cc.yunxi.common.domain.function.Convert;
import cc.yunxi.common.utils.BeanUtils;
import cc.yunxi.common.utils.CollUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

@ -1,5 +1,6 @@
package cc.yunxi.common.domain;
import cc.yunxi.common.domain.function.SFunction;
import cc.yunxi.common.utils.LambdaUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;

@ -0,0 +1,65 @@
package cc.yunxi.common.domain.convert;
import cc.yunxi.common.enums.BaseEnum;
import cc.yunxi.common.factory.StringCodeToEnumConverterFactory;
import com.baomidou.mybatisplus.annotation.IEnum;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.springframework.util.StringUtils;
import java.io.IOException;
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class EnumDeserializer extends JsonDeserializer<BaseEnum> implements ContextualDeserializer {
private Class<?> target;
public static final EnumDeserializer INSTANCE = new EnumDeserializer();
@SuppressWarnings("all")
@Override
public BaseEnum deserialize(JsonParser jsonParser, DeserializationContext ctx) throws IOException {
if (!StringUtils.hasText(jsonParser.getText())) {
return null;
}
// BaseEnum类 = target类相同 | tartget类的父类或接口
if (BaseEnum.class.isAssignableFrom(target)) {
return StringCodeToEnumConverterFactory.getEnum((Class) target, jsonParser.getText());
}
return defaultEnumTransform(target,jsonParser.getText());
}
/**
* @param ctx ctx
* @param property property
* @return 1
* @throws JsonMappingException
*/
@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctx, BeanProperty property) throws JsonMappingException {
Class<?> rawCls = ctx.getContextualType().getRawClass();
EnumDeserializer enumDeserializer = new EnumDeserializer();
enumDeserializer.setTarget(rawCls);
return enumDeserializer;
}
public static BaseEnum defaultEnumTransform(Class<?> type, String indexString) {
BaseEnum[] enumConstants = (BaseEnum[]) type.getEnumConstants();
try {
int index = Integer.parseInt(indexString);
return enumConstants[index];
} catch (NumberFormatException e) {
return null;
}
}
}

@ -0,0 +1,39 @@
package cc.yunxi.common.domain.convert;
import cc.yunxi.common.enums.BaseEnum;
import cc.yunxi.common.factory.StringCodeToEnumConverterFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.lang.reflect.Field;
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class EnumSerializer extends JsonSerializer<BaseEnum> {
public static final EnumSerializer INSTANCE = new EnumSerializer();
@Override
public void serialize(BaseEnum baseEnum, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
// java 如何获取枚举类的成员属性? 此处有问题, todo
jsonGenerator.writeStartObject();
Field[] fields = baseEnum.getClass().getFields();
for (Field field : fields) {
try {
jsonGenerator.writeStringField(field.getName(), String.valueOf(field.get(baseEnum)));
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
jsonGenerator.writeEndObject();
}
}

@ -1,10 +1,8 @@
package cc.yunxi.common.domain;
package cc.yunxi.common.domain.convert;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.IOException;
import java.time.Instant;

@ -1,4 +1,4 @@
package cc.yunxi.common.domain;
package cc.yunxi.common.domain.convert;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;

@ -1,8 +1,9 @@
package cc.yunxi.common.domain;
package cc.yunxi.common.domain.function;
/**
*
**/
@FunctionalInterface
public interface Convert<R,T>{
void convert(R origin, T target);
}

@ -1,4 +1,4 @@
package cc.yunxi.common.domain;
package cc.yunxi.common.domain.function;
import java.io.Serializable;

@ -0,0 +1,11 @@
package cc.yunxi.common.enums;
/**
*
*/
public interface BaseEnum {
/**
*
*/
String getCode();
}

@ -0,0 +1,16 @@
package cc.yunxi.common.enums;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Swagger
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SwaggerDisplayEnum {
String code() default "code";
String desc() default "desc";
}

@ -0,0 +1,71 @@
package cc.yunxi.common.factory;
import cc.yunxi.common.enums.BaseEnum;
import com.baomidou.mybatisplus.annotation.IEnum;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* ->
*/
public class StringCodeToEnumConverterFactory implements ConverterFactory<String, BaseEnum> {
private static final Map<Class, Converter> CONVERTERS = new HashMap<>();
/**
* String T T
*
* @param targetType
* @return
*/
@Override
public <T extends BaseEnum> Converter<String, T> getConverter(Class<T> targetType) {
Converter<String, T> converter = CONVERTERS.get(targetType);
if (converter == null) {
converter = new StringToEnumConverter<>(targetType);
CONVERTERS.put(targetType, converter);
}
return converter;
}
/**
*
* @param targetType
* @param source
* @return T
*/
public static <T extends BaseEnum> T getEnum(Class<T> targetType, String source) {
StringToEnumConverter enumConverter = new StringToEnumConverter(targetType);
return (T) enumConverter.convert(source);
}
/**
* ->
* org.springframework.core.convert.converter.Converter
*/
public static class StringToEnumConverter<T extends BaseEnum> implements Converter<String, T> {
private final Map<String, T> enumMap = new HashMap<>();
public StringToEnumConverter(Class<T> enumType) {
T[] enums = enumType.getEnumConstants();
for (T e : enums) {
enumMap.put(e.getCode().toString(), e);
}
}
@Override
public T convert(String source) {
T t = enumMap.get(source);
// Enum.valueOf(enumType, source); todo
if (Objects.isNull(t)) {
throw new IllegalArgumentException("无法匹配对应的枚举类型");
}
return t;
}
}
}

@ -1,6 +1,6 @@
package cc.yunxi.common.utils;
import cc.yunxi.common.domain.Convert;
import cc.yunxi.common.domain.function.Convert;
import cn.hutool.core.bean.BeanUtil;
import java.util.List;

@ -1,6 +1,6 @@
package cc.yunxi.common.utils;
import cc.yunxi.common.domain.SFunction;
import cc.yunxi.common.domain.function.SFunction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;

@ -4,7 +4,7 @@ import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("cc.yunxi.mapper")
@MapperScan(basePackages = "cc.yunxi.mapper")
@SpringBootApplication
public class NxhsApplication {
public static void main(String[] args) {

@ -36,7 +36,7 @@ public class JudgeUserAspect {
UserTypeEnum typeEnum = annotation.value();
UserDTO currentUser = UserContext.getUser();
log.info("请求控制器: {}, 当前用户信息: {}", methodSignature, currentUser);
if (currentUser == null || !Objects.equals(currentUser.getUserType(), typeEnum.getType())) {
if (currentUser == null || !Objects.equals(currentUser.getUserType(), typeEnum.getCode())) {
throw new UnauthorizedException("非法请求!");
}
} catch (Exception exception) {

@ -1,15 +1,17 @@
package cc.yunxi.config;
import cc.yunxi.common.factory.StringCodeToEnumConverterFactory;
import cc.yunxi.interceptor.LoginInterceptor;
import cc.yunxi.interceptor.StatsInterceptor;
import cn.hutool.core.collection.CollUtil;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.format.FormatterRegistry;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.*;
import java.util.Arrays;
import java.util.List;
@ -30,9 +32,48 @@ public class WebMvcConfig implements WebMvcConfigurer {
"/v3/**",
"/swagger-resources/**",
"/webjars/**",
"/static/**",
"/doc.html"
);
/**
* controller/api
*/
private Api api = new Api("/api", "cc.yunxi.**.controller.**");
@Getter
public static class Api {
/**
*
*/
private String prefix;
/**
*
*/
private String controllerPath;
public Api(String prefix, String controllerPath) {
this.prefix = prefix;
this.controllerPath = controllerPath;
}
}
/**
* 访
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 静态资源访问路径和存放路径配置
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/","classpath:/public/");
// swagger访问配置
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/","classpath:/META-INF/resources/webjars/");
}
/**
*
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 所有接口
@ -44,6 +85,40 @@ public class WebMvcConfig implements WebMvcConfigurer {
}
/**
*
*/
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
// 根据不同包匹配表达式,添加各自的统一前缀
configurePathMatch(configurer, api);
}
/**
* API controller RESTFul API (Swagger,Actuator Nginx)
*
* @param configurer
* @param api
*/
private void configurePathMatch(PathMatchConfigurer configurer, Api api) {
// 创建路径匹配类,指定以'.'分隔
AntPathMatcher antPathMatcher = new AntPathMatcher(".");
// 指定匹配前缀 类上有RestController注解 && 该类的包名匹配指定的自定义包的表达式
configurer.addPathPrefix(api.getPrefix(), clazz -> clazz.isAnnotationPresent(RestController.class)
&& antPathMatcher.match(api.getControllerPath(), clazz.getPackage().getName()));
}
/**
* addConverterFactory
* : get
*/
@Override
public void addFormatters(FormatterRegistry registry) {
// 枚举 转化器工厂类 code编码 => 枚举
registry.addConverterFactory(new StringCodeToEnumConverterFactory());
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 按顺序执行拦截器

@ -0,0 +1,17 @@
package cc.yunxi.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
*
*/
@Data
@Component
@ConfigurationProperties(prefix = "nxhs.wx.client")
public class WxShProperties {
private String appId;
private String appSecret;
}

@ -8,6 +8,7 @@ import cc.yunxi.domain.query.ClientQuery;
import cc.yunxi.domain.vo.ClientVO;
import cc.yunxi.service.IClientService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
@ -24,6 +25,7 @@ import org.springframework.web.bind.annotation.RestController;
* @author ccongli
* @since 2024-02-28 06:08:09
*/
@Api(tags = "散户接口")
@RestController
@RequestMapping("/client")
@RequiredArgsConstructor

@ -33,47 +33,25 @@ import javax.validation.Valid;
@Slf4j
public class CommonController {
private final String code2SessionUrl = "https://api.weixin.qq.com/sns/jscode2session";
private final CommonService commonService;
@Resource
private WxHsyProperties wxHsyProperties;
@Resource
private JwtTool jwtTool;
@ApiOperation("登录")
@PostMapping("/login")
public CommonResult<UserDTO> login(@Valid @RequestBody WxLoginDTO wxLoginDTO) {
log.info("login request body{}", wxLoginDTO);
String url = code2SessionUrl +"?appid=" + wxHsyProperties.getAppId() +
"&secret="+ wxHsyProperties.getAppSecret() +
"&js_code=" + wxLoginDTO.getCode() +
"&grant_type=authorization_code";
String jsonStr = HttpUtil.get(url, 30000);
log.info("WXserver code2Session return {}", jsonStr);
JSONObject jsonObject = JSONUtil.parseObj(jsonStr);
if (StrUtil.contains(jsonStr, "errcode")) {
throw new BizIllegalException("微信登录认证失败");
}
String openId = jsonObject.getStr("openid");
String sessionKey = jsonObject.getStr("session_key");
// String unionId = jsonObject.getStr("unionid");
// 解密得到用户手机号
String userInfo = WeChatUtil.decryptData(wxLoginDTO.getEncryptedData(), sessionKey, wxLoginDTO.getIv());
if (StringUtils.isEmpty(userInfo)) {
throw new BizIllegalException("微信认证信息错误");
}
// 判断用户类型,匹配登录时业务
UserDTO userDTO;
if(wxLoginDTO.getUserType().equals(UserTypeEnum.CLIENT.getType())) {
// 散户端登录业务
userDTO = commonService.loginByClient(userInfo, openId);
} else {
// 回收员端登录业务
userDTO = commonService.loginByRecycler(userInfo, openId);
}
@ApiOperation("回收员登录")
@PostMapping("/hsylogin")
public CommonResult<UserDTO> hsyLogin(@Valid @RequestBody WxLoginDTO wxLoginDTO) {
UserDTO userDTO = commonService.loginByRecycler(wxLoginDTO);
String token = jwtTool.createToken(userDTO);
userDTO.setToken(token);
return CommonResult.success(userDTO);
}
@ApiOperation("散户登录")
@PostMapping("/shlogin")
public CommonResult<UserDTO> shLogin(@Valid @RequestBody WxLoginDTO wxLoginDTO) {
// 散户端登录业务
UserDTO userDTO = commonService.loginByClient(wxLoginDTO);
String token = jwtTool.createToken(userDTO);
userDTO.setToken(token);
return CommonResult.success(userDTO);

@ -4,10 +4,13 @@ package cc.yunxi.controller;
import cc.yunxi.aspect.UserTypeAnnotation;
import cc.yunxi.common.domain.CommonResult;
import cc.yunxi.common.domain.PageDTO;
import cc.yunxi.common.utils.BeanUtils;
import cc.yunxi.domain.vo.recycleorder.RecycleOrderCreateVO;
import cc.yunxi.domain.po.RecycleOrder;
import cc.yunxi.domain.query.RecycleOrderQuery;
import cc.yunxi.domain.vo.recycleorder.RecycleOrderRespVO;
import cc.yunxi.domain.vo.recycleorder.RecycleOrderTakingVO;
import cc.yunxi.domain.vo.recycleorder.RecycleOrderUpdateVO;
import cc.yunxi.enums.UserTypeEnum;
import cc.yunxi.service.IRecycleOrderService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -15,17 +18,13 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
/**
* <p>
*
*
* </p>
*
* @author ccongli
@ -52,10 +51,35 @@ public class RecycleOrderController {
@ApiOperation("创建回收订单")
@PostMapping("/create")
@UserTypeAnnotation(UserTypeEnum.CLIENT)
public CommonResult<String> createOrder(@Valid @RequestBody RecycleOrderCreateVO orderCreateVO) {
// 1.分页查询
public CommonResult<String> createOrder(@RequestBody RecycleOrderCreateVO orderCreateVO) {
String orderId = recycleOrderService.createOrder(orderCreateVO);
return CommonResult.success(orderId);
}
@ApiOperation("回收订单详情")
@GetMapping("/info")
public CommonResult<RecycleOrderRespVO> findOrder(@RequestParam("id") String id) {
RecycleOrder recycleOrder = recycleOrderService.getOrderById(id);
RecycleOrderRespVO recycleOrderRespVO = BeanUtils.copyBean(recycleOrder, RecycleOrderRespVO.class);
return CommonResult.success(recycleOrderRespVO);
}
@ApiOperation("回收订单更新")
@PostMapping("/update")
@UserTypeAnnotation(UserTypeEnum.CLIENT)
public CommonResult<Boolean> updateOrder(@RequestBody RecycleOrderUpdateVO orderUpdateVO) {
recycleOrderService.updateOrder(orderUpdateVO);
return CommonResult.success(true);
}
@ApiOperation("回收员接单")
@PostMapping("/taking")
@UserTypeAnnotation(UserTypeEnum.CLIENT)
public CommonResult<Boolean> takingOrder(@RequestBody RecycleOrderTakingVO orderTakingVO) {
recycleOrderService.takingOrder(orderTakingVO);
return CommonResult.success(true);
}
}

@ -2,13 +2,13 @@ package cc.yunxi.controller;
import cc.yunxi.common.domain.CommonResult;
import cc.yunxi.common.exception.BadRequestException;
import cc.yunxi.domain.query.TestQuery;
import cc.yunxi.enums.UserTypeEnum;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
@Api(tags = "测试接口")
@RestController
@ -39,4 +39,12 @@ public class TestController {
log.error("error log...");
return CommonResult.success("ok");
}
@ApiOperation("测试枚举转换")
@PostMapping("/test04")
public CommonResult<TestQuery> enumConvert(@RequestBody TestQuery testQuery) {
return CommonResult.success(testQuery);
}
}

@ -8,7 +8,7 @@ import lombok.Data;
@Data
public class UserDTO {
private Integer userType; // 1 回收员 2 散户
private String userType; // 1 回收员 2 散户
private String id;
@ -16,6 +16,8 @@ public class UserDTO {
private String phone;
private String openid;
private String token; // 访问token
}

@ -24,5 +24,5 @@ public class WxLoginDTO {
@ApiModelProperty(value = "userType (1散户 2回收员)", required = true, example = "1")
@NotNull(message = "用户类型缺失")
private Integer userType;
private String userType;
}

@ -9,6 +9,7 @@ import java.time.LocalDateTime;
import java.util.Date;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@ -20,10 +21,9 @@ import lombok.Setter;
* @author ccongli
* @since 2024-02-28 06:08:09
*/
@Getter
@Setter
@Data
@TableName("nx_client")
@ApiModel(value = "Client对象", description = "散户信息")
@ApiModel(value = "Client", description = "散户信息")
public class Client {
@ApiModelProperty("主键id")

@ -11,8 +11,6 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
/**
* <p>
@ -25,7 +23,7 @@ import lombok.Setter;
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("nx_recycle_order")
@ApiModel(value = "RecycleOrder对象", description = "回收站回收订单")
@ApiModel(value = "RecycleOrder", description = "回收站回收订单")
public class RecycleOrder {
@ApiModelProperty("主键id")

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -17,6 +18,7 @@ import java.math.BigDecimal;
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("nx_recycle_station_staff")
@ApiModel(value = "Recycler", description = "回收站回收订单")
public class Recycler {
@TableId(value = "id", type = IdType.ASSIGN_ID)

@ -8,7 +8,7 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@ApiModel(description = "散户查询条件")
@ApiModel(value = "ClientQuery", description = "散户查询条件")
public class ClientQuery extends PageQuery {
@ApiModelProperty("联系电话")

@ -1,6 +1,7 @@
package cc.yunxi.domain.query;
import cc.yunxi.common.domain.PageQuery;
import cc.yunxi.enums.OrderStatusEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ -8,7 +9,7 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@ApiModel(description = "回收订单查询条件")
@ApiModel(value = "RecycleOrderQuery", description = "回收订单查询条件")
public class RecycleOrderQuery extends PageQuery {
@ApiModelProperty("订单编号")
@ -17,6 +18,7 @@ public class RecycleOrderQuery extends PageQuery {
@ApiModelProperty("订单状态")
private String status;
@ApiModelProperty("散户经度")
private Double longitude;

@ -8,7 +8,7 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@ApiModel(description = "回收员查询条件")
@ApiModel(value = "RecycleQuery", description = "回收员查询条件")
public class RecyclerQuery extends PageQuery {
@ApiModelProperty("所属回收站")

@ -0,0 +1,14 @@
package cc.yunxi.domain.query;
import cc.yunxi.enums.UserTypeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "TestQuery", description = "测试查询条件")
public class TestQuery {
@ApiModelProperty("UserTypeEnum枚举类")
private UserTypeEnum userType;
}

@ -3,9 +3,11 @@ package cc.yunxi.domain.vo.recycleorder;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.Future;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@ApiModel(description = "回收订单- App下单 Request VO")
@ -13,35 +15,29 @@ import java.time.LocalDateTime;
public class RecycleOrderCreateVO {
@ApiModelProperty(value = "回收站id", required = true, example = "521632060801030597")
@NotNull(message = "关联回收站不能为空")
@NotBlank(message = "关联回收站不能为空")
private String recycleStationId;
@ApiModelProperty(value = "订单类型", required = true, example = "1")
@NotNull(message = "订单类型不能为空")
private String orderType;
// @ApiModelProperty(value = "订单类型", required = true, example = "520193382480351557")
// @NotBlank(message = "订单类型不能为空")
// private String orderType;
@ApiModelProperty(value = "散户id", required = true, example = "521632060801030597")
@NotNull(message = "关联散户不能为空")
private String clientId;
@ApiModelProperty(value = "散户姓名", required = true, example = "张三")
@NotNull(message = "散户姓名不能为空")
private String clientName;
@ApiModelProperty(value = "散户手机号", required = true, example = "13264654521")
@NotNull(message = "散户手机号不能为空")
private String clientMobile;
// @ApiModelProperty(value = "散户id", required = true, example = "1763507031581421570")
// @NotBlank(message = "关联散户不能为空")
// private String clientId;
@ApiModelProperty(value = "散户地址", required = true, example = "xxx市yyy区")
@NotNull(message = "散户地址不能为空")
@NotBlank(message = "散户地址不能为空")
private String recycleAddress;
@ApiModelProperty(value = "预约上门时间起", required = true, example = "2024-03-01 15:58:49")
@NotNull(message = "预约上门时间起不能为空")
@Future(message = "预约上门时间起不正确")
private LocalDateTime appointmentTimeStart;
@ApiModelProperty(value = "预约上门时间止",required = true, example = "2024-03-01 15:58:49")
@NotNull(message = "预约上门时间止不能为空")
@Future(message = "预约上门时间止不正确")
private LocalDateTime appointmentTimeEnd;
@ApiModelProperty(value = "备注", required = false, example = "请尽快上门")

@ -29,13 +29,13 @@ public class RecycleOrderRespVO {
private String orderNumber;
@ApiModelProperty("订单类型")
private String orderTypeId;
private String orderType;
@ApiModelProperty("订单金额(元)")
private BigDecimal orderAmount;
@ApiModelProperty("订单状态")
private String orderStatusId;
private String orderStatus;
@ApiModelProperty("散户id")
private String clientId;

@ -0,0 +1,21 @@
package cc.yunxi.domain.vo.recycleorder;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@ApiModel(description = "回收订单- 接单 Request VO")
@Data
public class RecycleOrderTakingVO {
@ApiModelProperty(value = "回收订单id", required = true, example = "1763736089053364225")
@NotBlank(message = "回收订单id不能为空")
private String id;
// @ApiModelProperty(value = "回收员id", required = true, example = "533242995646951684")
// @NotBlank(message = "回收员id不能为空")
// private String staffsId;
}

@ -0,0 +1,37 @@
package cc.yunxi.domain.vo.recycleorder;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Future;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
@ApiModel(description = "回收订单- 编辑订单 Request VO")
@Data
public class RecycleOrderUpdateVO {
@ApiModelProperty(value = "回收订单id", required = true, example = "1763736089053364225")
@NotBlank(message = "回收订单id不能为空")
private String id;
@ApiModelProperty(value = "回收站id", required = true, example = "521632060801030597")
private String recycleStationId;
@ApiModelProperty(value = "散户地址", required = true, example = "xxx市yyy区")
private String recycleAddress;
@ApiModelProperty(value = "预约上门时间起", required = true, example = "2024-03-01 15:58:49")
@Future(message = "预约上门时间起不正确")
private LocalDateTime appointmentTimeStart;
@ApiModelProperty(value = "预约上门时间止",required = true, example = "2024-03-01 15:58:49")
@Future(message = "预约上门时间止不正确")
private LocalDateTime appointmentTimeEnd;
@ApiModelProperty(value = "备注", required = false, example = "请尽快上门")
private String remark;
}

@ -1,5 +1,6 @@
package cc.yunxi.enums;
import cc.yunxi.common.enums.BaseEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
@ -8,7 +9,7 @@ import lombok.Getter;
*/
@Getter
@AllArgsConstructor
public enum BusinessCodeEnum {
public enum BusinessCodeEnum implements BaseEnum {
ORDER("RO");

@ -1,6 +1,6 @@
package cc.yunxi.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import cc.yunxi.common.enums.SwaggerDisplayEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
@ -9,6 +9,7 @@ import lombok.Getter;
*/
@Getter
@AllArgsConstructor
@SwaggerDisplayEnum(code = "code", desc = "desc")
public enum OrderStatusEnum {
PENDING("520192817293693253", "待接单"),
@ -19,9 +20,9 @@ public enum OrderStatusEnum {
// @EnumValue
private final String statusId;
private final String code;
private final String statusName;
private final String desc;
}

@ -1,5 +1,6 @@
package cc.yunxi.enums;
import cc.yunxi.common.enums.SwaggerDisplayEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
@ -8,6 +9,7 @@ import lombok.Getter;
*/
@Getter
@AllArgsConstructor
@SwaggerDisplayEnum
public enum OrderTypeEnum {
SH_ORDER("520193382480351557", "散户下单"),
@ -18,9 +20,9 @@ public enum OrderTypeEnum {
ADM_ORDER("521999177572425477", "人工下单");
private final String typeId;
private final String code;
private final String typeName;
private final String desc;
}

@ -1,6 +1,8 @@
package cc.yunxi.enums;
import io.swagger.models.auth.In;
import cc.yunxi.common.enums.SwaggerDisplayEnum;
import cc.yunxi.common.enums.BaseEnum;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Getter;
@ -9,14 +11,16 @@ import lombok.Getter;
*/
@Getter
@AllArgsConstructor
public enum UserTypeEnum {
@SwaggerDisplayEnum
@JsonFormat(shape = JsonFormat.Shape.OBJECT) // 将枚举转换为JSON格式 返回给前端
public enum UserTypeEnum implements BaseEnum {
CLIENT(1, "散户"),
CLIENT("1", "散户"),
RECYCLER(2, "回收员");
RECYCLER("2", "回收员");
private final Integer type;
private final String code;
private final String name;
private final String desc;
}

@ -24,6 +24,13 @@ public interface IClientService extends IService<Client> {
*/
Page<Client> queryByPage(ClientQuery clientQuery);
/**
* id
* @param id
* @return Client
*/
Client getClientById(String id);
/**
* openid
@ -39,4 +46,6 @@ public interface IClientService extends IService<Client> {
* @return Client
*/
Client registerClient(String phoneNumber, String openId);
}

@ -2,6 +2,7 @@ package cc.yunxi.service;
import cc.yunxi.domain.dto.UserDTO;
import cc.yunxi.domain.dto.WxLoginDTO;
/**
*
@ -14,7 +15,7 @@ public interface ICommonService {
* @param openid
* @return
*/
UserDTO loginByRecycler(String userJson, String openid);
UserDTO loginByRecycler(WxLoginDTO wxLoginDTO);
/**
@ -23,5 +24,5 @@ public interface ICommonService {
* @param openid
* @return
*/
UserDTO loginByClient(String userJson, String openid);
UserDTO loginByClient(WxLoginDTO wxLoginDTO);
}

@ -5,9 +5,13 @@ import cc.yunxi.domain.po.Recycler;
import cc.yunxi.domain.query.RecycleOrderQuery;
import cc.yunxi.domain.query.RecyclerQuery;
import cc.yunxi.domain.vo.recycleorder.RecycleOrderCreateVO;
import cc.yunxi.domain.vo.recycleorder.RecycleOrderTakingVO;
import cc.yunxi.domain.vo.recycleorder.RecycleOrderUpdateVO;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import javax.validation.Valid;
/**
* <p>
*
@ -25,12 +29,32 @@ public interface IRecycleOrderService extends IService<RecycleOrder> {
*/
Page<RecycleOrder> queryOrderByPage(RecycleOrderQuery recycleOrderQuery);
/**
*
* @param id
* @return RecycleOrder
*/
RecycleOrder getOrderById(String id);
/**
*
* @param orderCreateVO
* @return ID
*/
String createOrder(RecycleOrderCreateVO orderCreateVO);
String createOrder(@Valid RecycleOrderCreateVO orderCreateVO);
/**
*
* @param orderUpdateVO
*/
void updateOrder(@Valid RecycleOrderUpdateVO orderUpdateVO);
/**
*
* @param orderTakingVO
*/
void takingOrder(@Valid RecycleOrderTakingVO orderTakingVO);
}

@ -1,6 +1,7 @@
package cc.yunxi.service.impl;
import cc.yunxi.common.exception.BizIllegalException;
import cc.yunxi.common.exception.DbException;
import cc.yunxi.domain.po.Client;
import cc.yunxi.domain.po.Recycler;
import cc.yunxi.domain.query.ClientQuery;
@ -14,6 +15,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
@ -40,13 +42,18 @@ public class ClientServiceImpl extends ServiceImpl<ClientMapper, Client> impleme
return clientPage;
}
@Override
public Client getClientById(String id) {
return this.getById(id);
}
@Override
public Client getClientByOpenid(String openid) {
Client client = lambdaQuery().eq(Client::getWxOpenid, openid).one();
return client;
return lambdaQuery().eq(Client::getWxOpenid, openid).one();
}
@Override
@Transactional
public Client registerClient(String phoneNumber, String openId) {
// 判断手机号是否被注册
Client client = lambdaQuery().eq(Client::getMobilePhone, phoneNumber).one();
@ -60,4 +67,11 @@ public class ClientServiceImpl extends ServiceImpl<ClientMapper, Client> impleme
this.save(client);
return client;
}
// 校验散户是否存在
private void validateClientExists(String id) {
if (this.getClientById(id) == null) {
throw new DbException("散户不存在");
}
}
}

@ -1,15 +1,25 @@
package cc.yunxi.service.impl;
import cc.yunxi.common.exception.BizIllegalException;
import cc.yunxi.config.WxHsyProperties;
import cc.yunxi.config.WxShProperties;
import cc.yunxi.domain.dto.UserDTO;
import cc.yunxi.domain.dto.WxLoginDTO;
import cc.yunxi.domain.po.Client;
import cc.yunxi.domain.po.Recycler;
import cc.yunxi.enums.UserTypeEnum;
import cc.yunxi.service.IClientService;
import cc.yunxi.service.ICommonService;
import cc.yunxi.service.IRecyclerService;
import cc.yunxi.utils.JwtTool;
import cc.yunxi.utils.WeChatUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
@ -17,6 +27,7 @@ import javax.annotation.Resource;
*
*/
@Service
@Slf4j
public class CommonService implements ICommonService {
@Resource
@ -25,37 +36,75 @@ public class CommonService implements ICommonService {
@Resource
private IClientService clientService;
@Resource
private WxHsyProperties wxHsyProperties;
@Resource
private WxShProperties wxShProperties;
private static final String code2SessionUrl = "https://api.weixin.qq.com/sns/jscode2session";
private UserDTO wxAuthentication(WxLoginDTO wxLoginDTO) {
log.info("login request body{}", wxLoginDTO);
// String url = code2SessionUrl +"?appid=" + wxHsyProperties.getAppId() +
// "&secret="+ wxHsyProperties.getAppSecret() +
// "&js_code=" + wxLoginDTO.getCode() +
// "&grant_type=authorization_code";
String url = code2SessionUrl + "?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";
if (wxLoginDTO.getUserType().equals(UserTypeEnum.CLIENT.getCode())) {
url = String.format(url, wxShProperties.getAppId(), wxShProperties.getAppSecret(), wxLoginDTO.getCode());
} else {
url = String.format(url, wxHsyProperties.getAppId(), wxHsyProperties.getAppSecret(), wxLoginDTO.getCode());
}
String jsonStr = HttpUtil.get(url, 30000);
log.info("WXserver code2Session return {}", jsonStr);
JSONObject jsonObject = JSONUtil.parseObj(jsonStr);
if (StrUtil.contains(jsonStr, "errcode")) {
throw new BizIllegalException("微信登录认证失败");
}
String openId = jsonObject.getStr("openid");
String sessionKey = jsonObject.getStr("session_key");
// String unionId = jsonObject.getStr("unionid");
// 解密得到用户手机号
String userInfo = WeChatUtil.decryptData(wxLoginDTO.getEncryptedData(), sessionKey, wxLoginDTO.getIv());
if (StringUtils.isEmpty(userInfo)) {
throw new BizIllegalException("微信认证信息错误");
}
JSONObject userObject = JSONUtil.parseObj(userInfo);
String phoneNumber = userObject.getStr("phoneNumber");
UserDTO userDTO = new UserDTO();
userDTO.setOpenid(openId);
userDTO.setPhone(phoneNumber);
return userDTO;
}
@Override
public UserDTO loginByRecycler(String userJson, String openid) {
Recycler recycler = recyclerService.getRecyclerByOpenid(openid);
public UserDTO loginByRecycler(WxLoginDTO wxLoginDTO) {
UserDTO userDTO = wxAuthentication(wxLoginDTO);
Recycler recycler = recyclerService.getRecyclerByOpenid(userDTO.getOpenid());
if (recycler == null) {
// 回收员不存在,则注册
JSONObject userObject = JSONUtil.parseObj(userJson);
String phoneNumber = userObject.getStr("phoneNumber");
recycler = recyclerService.registerRecycler(phoneNumber, openid);
recycler = recyclerService.registerRecycler(userDTO.getPhone(), userDTO.getOpenid());
}
UserDTO userDTO = new UserDTO();
userDTO.setId(recycler.getId());
userDTO.setUserType(UserTypeEnum.RECYCLER.getType());
userDTO.setUserType(UserTypeEnum.RECYCLER.getCode());
userDTO.setUsername(recycler.getStaffsName());
userDTO.setPhone(recycler.getMobilePhone());
return userDTO;
}
@Override
public UserDTO loginByClient(String userJson, String openid) {
Client client = clientService.getClientByOpenid(openid);
public UserDTO loginByClient(WxLoginDTO wxLoginDTO) {
UserDTO userDTO = wxAuthentication(wxLoginDTO);
Client client = clientService.getClientByOpenid(userDTO.getOpenid());
if (client == null) {
// 散户不存在,则注册
JSONObject userObject = JSONUtil.parseObj(userJson);
String phoneNumber = userObject.getStr("phoneNumber");
client = clientService.registerClient(phoneNumber, openid);
client = clientService.registerClient(userDTO.getPhone(), userDTO.getOpenid());
}
UserDTO userDTO = new UserDTO();
userDTO.setId(client.getId());
userDTO.setUserType(UserTypeEnum.CLIENT.getType());
userDTO.setUserType(UserTypeEnum.CLIENT.getCode());
userDTO.setUsername(client.getNickName());
userDTO.setPhone(client.getMobilePhone());
return userDTO;
}
}

@ -1,20 +1,34 @@
package cc.yunxi.service.impl;
import cc.yunxi.common.exception.DbException;
import cc.yunxi.common.utils.BeanUtils;
import cc.yunxi.common.utils.CommonUtil;
import cc.yunxi.domain.dto.UserDTO;
import cc.yunxi.domain.po.Client;
import cc.yunxi.domain.po.RecycleOrder;
import cc.yunxi.domain.po.Recycler;
import cc.yunxi.domain.query.RecycleOrderQuery;
import cc.yunxi.domain.vo.recycleorder.RecycleOrderCreateVO;
import cc.yunxi.domain.vo.recycleorder.RecycleOrderTakingVO;
import cc.yunxi.domain.vo.recycleorder.RecycleOrderUpdateVO;
import cc.yunxi.enums.BusinessCodeEnum;
import cc.yunxi.enums.OrderStatusEnum;
import cc.yunxi.enums.OrderTypeEnum;
import cc.yunxi.mapper.RecycleOrderMapper;
import cc.yunxi.service.IClientService;
import cc.yunxi.service.IRecycleOrderService;
import cc.yunxi.utils.UserContext;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import javax.validation.Valid;
/**
* <p>
@ -25,8 +39,11 @@ import org.springframework.transaction.annotation.Transactional;
* @since 2024-03-01 11:15:39
*/
@Service
@Validated
public class RecycleOrderServiceImpl extends ServiceImpl<RecycleOrderMapper, RecycleOrder> implements IRecycleOrderService {
@Resource
private IClientService clientService;
public Page<RecycleOrder> queryOrderByPage(RecycleOrderQuery recycleOrderQuery) {
QueryWrapper<RecycleOrder> wrapper = new QueryWrapper<>();
@ -39,14 +56,57 @@ public class RecycleOrderServiceImpl extends ServiceImpl<RecycleOrderMapper, Rec
return recycleOrderPage;
}
public RecycleOrder getOrderById(String id) {
return this.getById(id);
}
@Override
@Transactional(rollbackFor = Exception.class)
public String createOrder(RecycleOrderCreateVO orderCreateVO) {
// 查询散户是否存在
UserDTO userDTO = UserContext.getUser();
Client client = clientService.getClientById(userDTO.getId());
if (ObjectUtil.isEmpty(client)) {
throw new DbException("散户不存在");
}
RecycleOrder recycleOrder = BeanUtils.copyBean(orderCreateVO, RecycleOrder.class);
String idNumber = CommonUtil.getIdNumber(BusinessCodeEnum.ORDER.getCode());
recycleOrder.setClientId(client.getId());
recycleOrder.setClientName(client.getNickName());
recycleOrder.setClientMobile(client.getMobilePhone());
recycleOrder.setOrderNumber(idNumber);
recycleOrder.setOrderType(OrderTypeEnum.SH_ORDER.getCode());
recycleOrder.setOrderStatus(OrderStatusEnum.PENDING.getCode());
this.save(recycleOrder);
return recycleOrder.getId();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateOrder(RecycleOrderUpdateVO orderUpdateVO) {
validateOrderExists(orderUpdateVO.getId());
RecycleOrder recycleOrder = BeanUtils.copyBean(orderUpdateVO, RecycleOrder.class);
this.updateById(recycleOrder);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void takingOrder(RecycleOrderTakingVO orderTakingVO) {
UserDTO userDTO = UserContext.getUser();
validateOrderExists(userDTO.getId());
RecycleOrder recycleOrder = BeanUtils.copyBean(orderTakingVO, RecycleOrder.class);
recycleOrder.setOrderStatus(OrderStatusEnum.UNPROCESSED.getCode());
this.updateById(recycleOrder);
}
// 校验订单是否存在
private void validateOrderExists(String id) {
if (this.getOrderById(id) == null) {
throw new DbException("回收订单不存在");
}
}
}

@ -1,11 +1,10 @@
server:
port: 8080
servlet:
context-path: /api
spring:
application:
name: nxhs-service
profiles:
active: dev
datasource:
@ -67,9 +66,13 @@ nxhs:
tokenTTL: 30d
auth:
excludePaths:
- /common/login
- /test/**
- /api/common/hsylogin
- /api/common/shlogin
- /api/test/**
wx:
client: # 散户端
appid: wx630bc4f43990c80c
appsecret: 37028048aad5e1877c2b2aeacdfdc01b
recycler: # 回收员端
appid: wxf82bcc798891a29d
appsecret: f37fb0ab2b5f691d8507acced60a58fb

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 KiB

@ -1,9 +1,10 @@
package cc.yunxi;
import cc.yunxi.common.utils.LambdaUtil;
import cc.yunxi.common.domain.SFunction;
import cc.yunxi.common.domain.function.SFunction;
import cc.yunxi.domain.dto.UserDTO;
import cc.yunxi.domain.po.Recycler;
import cc.yunxi.enums.UserTypeEnum;
import cc.yunxi.service.ITestService;
import cc.yunxi.utils.JwtTool;
import org.junit.jupiter.api.Test;
@ -48,8 +49,9 @@ public class NxhsApplicationTest {
}
public static void main(String[] args) {
String property = System.getProperty("user.dir");
System.out.println(property);
// String property = System.getProperty("user.dir");
// System.out.println(property);
System.out.println(UserTypeEnum.CLIENT.toString());
}
}

Loading…
Cancel
Save