提交 1442dee6 作者: 余乾开

Merge branch 'develop'

...@@ -21,5 +21,9 @@ public class LoginSuccessDTO implements Serializable { ...@@ -21,5 +21,9 @@ public class LoginSuccessDTO implements Serializable {
private String token; private String token;
private Integer userAccountId; private Integer userAccountId;
private String accountNo; private String accountNo;
private String uid;
private String phoneNum;
private String userName;
private String nickName;
// private RoleInfoDTO roleInfo; // private RoleInfoDTO roleInfo;
} }
...@@ -22,6 +22,7 @@ public enum ResultEnum implements BaseErrorInfoInterface{ ...@@ -22,6 +22,7 @@ public enum ResultEnum implements BaseErrorInfoInterface{
PASSWORD_INCONSISTENT("5026", "新密码与确认密码不一致,请确认一致"), PASSWORD_INCONSISTENT("5026", "新密码与确认密码不一致,请确认一致"),
WX_ACCESS_TOKEN_ERROR("5027", "获取微信AccessToken失败"), WX_ACCESS_TOKEN_ERROR("5027", "获取微信AccessToken失败"),
APPLET_QR_CODE_CREATE_ERROR("5030", "生成小程序码错误:"), APPLET_QR_CODE_CREATE_ERROR("5030", "生成小程序码错误:"),
AUTH_PHONE_NUMBER_ERROR("5031", "授权手机号失败"),
PWD_CREATE_ERROR("6001", "创建密码失败"), PWD_CREATE_ERROR("6001", "创建密码失败"),
PWD_CONPARED_ERROR("6002", "密码错误"), PWD_ALERT_ERROR("6003", "密码不一致"), PWD_CONPARED_ERROR("6002", "密码错误"), PWD_ALERT_ERROR("6003", "密码不一致"),
......
package com.mmc.iuav.user.auth;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;
import java.util.Objects;
/**
* Author: geDuo
* Date: 2022/6/2 17:26
*/
@Configuration
public class DataFilterYml {
@Bean
public static PropertySourcesPlaceholderConfigurer loadYml(){
PropertySourcesPlaceholderConfigurer configurer=new PropertySourcesPlaceholderConfigurer();
YamlPropertiesFactoryBean yaml=new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("not-check.yml"));
configurer.setProperties(Objects.requireNonNull(yaml.getObject()));
return configurer;
}
}
package com.mmc.iuav.user.auth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author: zj
* @Date: 2023/5/28 10:52
*/
@Configuration
public class MvcConfiguration implements WebMvcConfigurer {
@Autowired
private TokenCheckHandleInterceptor tokenCheckHandleInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenCheckHandleInterceptor);
WebMvcConfigurer.super.addInterceptors(registry);
}
}
package com.mmc.iuav.user.auth;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import java.util.List;
/**
* @author: zj
* @Date: 2023/5/28 13:54
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "data-filter", ignoreUnknownFields = false)
@PropertySource("classpath:not-check.yml")
public class NotCheckUriConfig {
// 不需要验证token的请求地址
private List<String> notAuthPath;
// 不需要验证token的请求地址;// 不需要验证token的请求地址
private List<String> uploadPath;
}
package com.mmc.iuav.user.auth;
import com.alibaba.fastjson2.JSONObject;
import com.mmc.iuav.response.ResultBody;
import com.mmc.iuav.response.ResultEnum;
import com.mmc.iuav.user.model.dto.LoginSuccessDTO;
import com.mmc.iuav.user.util.PathUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
/**
* @author: zj
* @Date: 2023/5/28 10:46
*/
@Component
public class TokenCheckHandleInterceptor implements HandlerInterceptor {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private NotCheckUriConfig notCheckUriConfig;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// String requestURI = request.getRequestURI();
// //根据uri确认是否要拦截
// if (!shouldFilter(requestURI)){
// return true;
// }
// String token = request.getHeader("token");
// String tokenJson = stringRedisTemplate.opsForValue().get(token);
//
// if (StringUtils.isBlank(tokenJson)){
// exceptionProcess(response);
// return false;
// }
// LoginSuccessDTO loginSuccessDTO = JSONObject.parseObject(tokenJson, LoginSuccessDTO.class);
// if (loginSuccessDTO != null){
// request.setAttribute("userAccountId", loginSuccessDTO.getUserAccountId());
// }
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
public void exceptionProcess(HttpServletResponse response) throws Exception{
response.setContentType("application/json;charset=utf-8");
PrintWriter writer=response.getWriter();
writer.write(ResultBody.error(ResultEnum.LOGIN_ACCOUNT_STATUS_ERROR).toString());
writer.close();
}
private boolean shouldFilter(String path) {
// 路径与配置的相匹配,则执行过滤
for (String pathPattern : notCheckUriConfig.getNotAuthPath()) {
if (PathUtil.isPathMatch(pathPattern, path)) {
// 如果匹配
return false;
}
}
return true;
}
}
...@@ -11,6 +11,8 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -11,6 +11,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
/** /**
* @author: zj * @author: zj
* @Date: 2023/5/15 15:50 * @Date: 2023/5/15 15:50
......
...@@ -5,6 +5,7 @@ import com.mmc.iuav.group.Update; ...@@ -5,6 +5,7 @@ import com.mmc.iuav.group.Update;
import com.mmc.iuav.group.UpdatePassword; import com.mmc.iuav.group.UpdatePassword;
import com.mmc.iuav.response.ResultBody; import com.mmc.iuav.response.ResultBody;
import com.mmc.iuav.user.model.dto.BaseAccountDTO; import com.mmc.iuav.user.model.dto.BaseAccountDTO;
import com.mmc.iuav.user.model.dto.LoginSuccessDTO;
import com.mmc.iuav.user.model.dto.UserAccountSimpleDTO; import com.mmc.iuav.user.model.dto.UserAccountSimpleDTO;
import com.mmc.iuav.user.model.qo.BUserAccountQO; import com.mmc.iuav.user.model.qo.BUserAccountQO;
import com.mmc.iuav.user.model.vo.BUserAccountVO; import com.mmc.iuav.user.model.vo.BUserAccountVO;
...@@ -17,6 +18,7 @@ import org.springframework.web.bind.annotation.*; ...@@ -17,6 +18,7 @@ import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore; import springfox.documentation.annotations.ApiIgnore;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.List; import java.util.List;
...@@ -49,7 +51,7 @@ public class BackUserAccountController extends BaseController{ ...@@ -49,7 +51,7 @@ public class BackUserAccountController extends BaseController{
@ApiOperation(value = "账号-删除") @ApiOperation(value = "账号-删除")
@ApiResponses({@ApiResponse(code = 200, message = "OK", response = ResultBody.class)}) @ApiResponses({@ApiResponse(code = 200, message = "OK", response = ResultBody.class)})
@PostMapping("removeBAccount") @PostMapping("removeBAccount")
public ResultBody removeBAccount(@RequestParam Integer userAccountId) { public ResultBody removeBAccount(@RequestParam Integer userAccountId, HttpServletRequest request) {
return userAccountService.removeBAccount(userAccountId); return userAccountService.removeBAccount(userAccountId);
} }
...@@ -88,6 +90,6 @@ public class BackUserAccountController extends BaseController{ ...@@ -88,6 +90,6 @@ public class BackUserAccountController extends BaseController{
@ApiResponses({@ApiResponse(code = 200, message = "OK", response = ResultBody.class)}) @ApiResponses({@ApiResponse(code = 200, message = "OK", response = ResultBody.class)})
@PostMapping("listTest") @PostMapping("listTest")
public ResultBody listTest(HttpServletRequest request) { public ResultBody listTest(HttpServletRequest request) {
return ResultBody.success(this.getUserLoginInfo(request)); return ResultBody.success();
} }
} }
package com.mmc.iuav.user.controller; package com.mmc.iuav.user.controller;
import com.alibaba.fastjson2.JSONObject;
import com.mmc.iuav.auth.JwtConstant; import com.mmc.iuav.auth.JwtConstant;
import com.mmc.iuav.auth.JwtUtil; import com.mmc.iuav.auth.JwtUtil;
import com.mmc.iuav.http.BizException; import com.mmc.iuav.http.BizException;
import com.mmc.iuav.response.ResultEnum;
import com.mmc.iuav.user.model.dto.BaseAccountDTO; import com.mmc.iuav.user.model.dto.BaseAccountDTO;
import com.mmc.iuav.user.model.dto.LoginSuccessDTO;
import io.jsonwebtoken.Claims; import io.jsonwebtoken.Claims;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
...@@ -14,21 +20,39 @@ import javax.servlet.http.HttpServletRequest; ...@@ -14,21 +20,39 @@ import javax.servlet.http.HttpServletRequest;
*/ */
public abstract class BaseController { public abstract class BaseController {
@Autowired
private StringRedisTemplate stringRedisTemplate;
/** /**
* 解析token,获取用户信息 * 解析token,获取用户信息
* @param request * @param request
* @return * @return
*/ */
public BaseAccountDTO getUserLoginInfo(HttpServletRequest request) { // public BaseAccountDTO getUserLoginInfo(HttpServletRequest request) {
// String token = request.getHeader("token");
// try {
// Claims claims = JwtUtil.parseJwt(token);
// String userId = claims.get(JwtConstant.USER_ACCOUNT_ID).toString();
//// String roleId = claims.get("").toString();
// String tokenType = claims.get(JwtConstant.TOKEN_TYPE).toString();
// return BaseAccountDTO.builder().id(Integer.parseInt(userId)).tokenPort(tokenType).build();
// }catch (Exception e){
// throw new BizException("Invalid token");
// }
// }
/**
* 使用token从redis获取用户信息
* @param request
* @return
*/
public LoginSuccessDTO getUserLoginInfoFromRedis(HttpServletRequest request) {
String token = request.getHeader("token"); String token = request.getHeader("token");
try { String json = stringRedisTemplate.opsForValue().get(token);
Claims claims = JwtUtil.parseJwt(token); if (StringUtils.isBlank(json)){
String userId = claims.get(JwtConstant.USER_ACCOUNT_ID).toString(); throw new BizException(ResultEnum.LOGIN_ACCOUNT_STATUS_ERROR);
// String roleId = claims.get("").toString();
String tokenType = claims.get(JwtConstant.TOKEN_TYPE).toString();
return BaseAccountDTO.builder().id(Integer.parseInt(userId)).tokenPort(tokenType).build();
}catch (Exception e){
throw new BizException("Invalid token");
} }
LoginSuccessDTO loginSuccessDTO = JSONObject.parseObject(json, LoginSuccessDTO.class);
return loginSuccessDTO;
} }
} }
...@@ -5,10 +5,7 @@ import com.mmc.iuav.response.ResultBody; ...@@ -5,10 +5,7 @@ import com.mmc.iuav.response.ResultBody;
import com.mmc.iuav.user.model.dto.UserAccountSimpleDTO; import com.mmc.iuav.user.model.dto.UserAccountSimpleDTO;
import com.mmc.iuav.user.model.vo.UserAccountVO; import com.mmc.iuav.user.model.vo.UserAccountVO;
import com.mmc.iuav.user.service.UserAccountService; import com.mmc.iuav.user.service.UserAccountService;
import io.swagger.annotations.Api; import io.swagger.annotations.*;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
...@@ -32,7 +29,7 @@ public class UserAccountController extends BaseController{ ...@@ -32,7 +29,7 @@ public class UserAccountController extends BaseController{
@ApiResponses({ @ApiResponse(code = 200, message = "OK", response = UserAccountVO.class) }) @ApiResponses({ @ApiResponse(code = 200, message = "OK", response = UserAccountVO.class) })
@GetMapping("info") @GetMapping("info")
public ResultBody info(HttpServletRequest request) { public ResultBody info(HttpServletRequest request) {
return ResultBody.success(userAccountService.getUserAccountById(this.getUserLoginInfo(request).getId())); return ResultBody.success(userAccountService.getUserAccountById(this.getUserLoginInfoFromRedis(request).getUserAccountId()));
} }
@ApiOperation(value = "修改用户信息") @ApiOperation(value = "修改用户信息")
...@@ -56,4 +53,12 @@ public class UserAccountController extends BaseController{ ...@@ -56,4 +53,12 @@ public class UserAccountController extends BaseController{
return userAccountService.feignListUserAccountIds(provinceCode, cityCode, districtCode); return userAccountService.feignListUserAccountIds(provinceCode, cityCode, districtCode);
} }
@ApiOperation(value = "授权手机号")
@ApiResponses({ @ApiResponse(code = 200, message = "OK", response = Integer.class) })
@GetMapping("getUserPhoneNumber")
public ResultBody getUserPhoneNumber(HttpServletRequest request,
@ApiParam(value = "授权手机号code", required = true) @RequestParam String code) {
return userAccountService.getUserPhoneNumber(this.getUserLoginInfoFromRedis(request).getUserAccountId(), code);
}
} }
...@@ -18,7 +18,7 @@ import java.io.PrintWriter; ...@@ -18,7 +18,7 @@ import java.io.PrintWriter;
@Api(tags = "微信相关接口") @Api(tags = "微信相关接口")
@RequestMapping("/wx/") @RequestMapping("/wx/")
@RestController @RestController
public class WxController { public class WxController extends BaseController {
@Autowired @Autowired
private WxService wxService; private WxService wxService;
...@@ -26,15 +26,15 @@ public class WxController { ...@@ -26,15 +26,15 @@ public class WxController {
@ApiOperation(value = "小程序-获取当前用户的小程序推荐码") @ApiOperation(value = "小程序-获取当前用户的小程序推荐码")
@ApiResponses({ @ApiResponse(code = 200, message = "OK", response = String.class) }) @ApiResponses({ @ApiResponse(code = 200, message = "OK", response = String.class) })
@PostMapping("getAppletRcdCode") @PostMapping("getAppletRcdCode")
public ResultBody getAppletRcdCode(HttpServletRequest request) { public ResultBody getAppletRcdCode(HttpServletRequest request, @ApiParam(value = "小程序路径",example = "pages/welcome/index") @RequestParam String page) {
return null; return wxService.getUnLimitedQRCode(page, "currentUserAccountId=" + this.getUserLoginInfoFromRedis(request).getUserAccountId());
} }
@ApiOperation(value = "小程序-测试专用") @ApiOperation(value = "小程序-测试专用")
@ApiResponses({ @ApiResponse(code = 200, message = "OK", response = ResultBody.class) }) @ApiResponses({ @ApiResponse(code = 200, message = "OK", response = ResultBody.class) })
@PostMapping("testDemo") @PostMapping("testDemo")
public ResultBody testDemo() { public ResultBody testDemo() {
return ResultBody.success("app:" + wxService.getAccessToken() + "sub: " + wxService.getSubAccessToken()); return ResultBody.success("app:" + "wxService.getAccessToken()" + "sub: " + wxService.getSubAccessToken());
} }
/** /**
...@@ -54,7 +54,7 @@ public class WxController { ...@@ -54,7 +54,7 @@ public class WxController {
return ResultBody.success(wxService.createUrlLink(path, query)); return ResultBody.success(wxService.createUrlLink(path, query));
} }
@ApiOperation(value = "监控微信公众号的事件变化通知") @ApiOperation(value = "监控微信公众号的事件变化通知", hidden = true)
@ApiResponses({ @ApiResponse(code = 200, message = "OK", response = String.class) }) @ApiResponses({ @ApiResponse(code = 200, message = "OK", response = String.class) })
@PostMapping("wxSendMessage") @PostMapping("wxSendMessage")
public void wxSendMessage(HttpServletRequest req, HttpServletResponse resp) throws IOException { public void wxSendMessage(HttpServletRequest req, HttpServletResponse resp) throws IOException {
...@@ -65,4 +65,11 @@ public class WxController { ...@@ -65,4 +65,11 @@ public class WxController {
String msg = wxService.receiveSubAccountEvents(req); String msg = wxService.receiveSubAccountEvents(req);
out.println(msg); out.println(msg);
} }
@ApiOperation(value = "生成小程序码")
@ApiResponses({ @ApiResponse(code = 200, message = "OK", response = ResultBody.class) })
@GetMapping("getAppletQRCode")
public ResultBody getAppletQRCode(@ApiParam(value = "小程序路径",example = "pages/welcome/index") @RequestParam String page,@ApiParam(value = "参数",example = "name=123&sex=456") @RequestParam String scene) {
return wxService.getUnLimitedQRCode(page, scene);
}
} }
...@@ -44,6 +44,9 @@ public class UserAccountDO implements Serializable { ...@@ -44,6 +44,9 @@ public class UserAccountDO implements Serializable {
private Integer cityCode; private Integer cityCode;
private Integer districtCode; private Integer districtCode;
private Integer cooperationTagId;
private Integer companyAuthStatus;
public UserAccountDO(UserAccountVO userAccountVO) { public UserAccountDO(UserAccountVO userAccountVO) {
this.id = userAccountVO.getId(); this.id = userAccountVO.getId();
this.phoneNum = userAccountVO.getPhoneNum(); this.phoneNum = userAccountVO.getPhoneNum();
...@@ -73,12 +76,13 @@ public class UserAccountDO implements Serializable { ...@@ -73,12 +76,13 @@ public class UserAccountDO implements Serializable {
public UserAccountVO buildUserAccountVO() { public UserAccountVO buildUserAccountVO() {
return UserAccountVO.builder().id(this.id).uid(this.uid).accountNo(this.accountNo).accountType(this.accountType).phoneNum(this.phoneNum).userName(this.userName).nickName(this.nickName) return UserAccountVO.builder().id(this.id).uid(this.uid).accountNo(this.accountNo).accountType(this.accountType).phoneNum(this.phoneNum).userName(this.userName).nickName(this.nickName)
.userImg(this.userImg).userSex(this.userSex).email(this.email).source(this.source).accountStatus(this.accountStatus).remark(this.remark).portType(this.portType) .userImg(this.userImg).userSex(this.userSex).email(this.email).source(this.source).accountStatus(this.accountStatus).remark(this.remark).portType(this.portType)
.createTime(this.createTime).build(); .createTime(this.createTime).companyAuthStatus(this.companyAuthStatus).cooperationTagId(this.cooperationTagId).build();
} }
public UserAccountSimpleDTO buildUserAccountSimpleDTO() { public UserAccountSimpleDTO buildUserAccountSimpleDTO() {
return UserAccountSimpleDTO.builder().id(this.id).uid(this.uid).accountNo(this.accountNo).accountType(this.accountType).phoneNum(this.phoneNum).userName(this.userName).nickName(this.nickName) return UserAccountSimpleDTO.builder().id(this.id).uid(this.uid).accountNo(this.accountNo).accountType(this.accountType).phoneNum(this.phoneNum).userName(this.userName).nickName(this.nickName)
.userImg(this.userImg).userSex(this.userSex).email(this.email).source(this.source).accountStatus(this.accountStatus).portType(this.portType) .userImg(this.userImg).userSex(this.userSex).email(this.email).source(this.source).accountStatus(this.accountStatus).portType(this.portType)
.companyAuthStatus(this.companyAuthStatus == null || this.companyAuthStatus != 1 ? 0 : 1).cooperationTagId(this.cooperationTagId)
.build(); .build();
} }
} }
...@@ -115,4 +115,12 @@ public interface UserAccountService { ...@@ -115,4 +115,12 @@ public interface UserAccountService {
* @return * @return
*/ */
ResultBody feignAuthUserPwd(Integer id, String authPwd); ResultBody feignAuthUserPwd(Integer id, String authPwd);
/**
* 授权手机号
* @param id
* @param code
* @return
*/
ResultBody getUserPhoneNumber(Integer id, String code);
} }
...@@ -6,7 +6,6 @@ import com.mmc.iuav.user.model.vo.WxLoginVO; ...@@ -6,7 +6,6 @@ import com.mmc.iuav.user.model.vo.WxLoginVO;
import com.mmc.iuav.user.model.vo.WxMsgVO; import com.mmc.iuav.user.model.vo.WxMsgVO;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/** /**
* @author: zj * @author: zj
...@@ -64,5 +63,20 @@ public interface WxService { ...@@ -64,5 +63,20 @@ public interface WxService {
*/ */
ResultBody sendAppletMsg(AppletMsgVO appletMsgVO); ResultBody sendAppletMsg(AppletMsgVO appletMsgVO);
/**
* 生成小程序链接
* @param path
* @param query
* @return
*/
String createUrlLink(String path, String query); String createUrlLink(String path, String query);
/**
* 获取用户授权手机号
*
* @param id
* @param code
* @return
*/
String getUserPhoneNumber(Integer id, String code);
} }
...@@ -22,11 +22,13 @@ import com.mmc.iuav.user.service.WxService; ...@@ -22,11 +22,13 @@ import com.mmc.iuav.user.service.WxService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit;
/** /**
* @author: zj * @author: zj
...@@ -42,6 +44,9 @@ public class AuthServiceImpl implements AuthService { ...@@ -42,6 +44,9 @@ public class AuthServiceImpl implements AuthService {
@Autowired @Autowired
private UserAccountService userAccountService; private UserAccountService userAccountService;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override @Override
public ResultBody appletLogin(WxLoginVO wxLoginVO) { public ResultBody appletLogin(WxLoginVO wxLoginVO) {
String unionId; String unionId;
...@@ -82,11 +87,13 @@ public class AuthServiceImpl implements AuthService { ...@@ -82,11 +87,13 @@ public class AuthServiceImpl implements AuthService {
} }
//数据库查询用户信息 //数据库查询用户信息
UserAccountVO userAccountVO = userAccountService.getUserAccountInfoByUnionId(unionId); UserAccountVO userAccountVO = userAccountService.getUserAccountInfoByUnionId(unionId);
String uid = userAccountVO.getUid();
if (userAccountVO == null) { if (userAccountVO == null) {
UserAccountDO userAccountDO = new UserAccountDO(); UserAccountDO userAccountDO = new UserAccountDO();
userAccountDO.setUnionId(unionId); userAccountDO.setUnionId(unionId);
userAccountDO.setOpenId(openId); userAccountDO.setOpenId(openId);
userAccountDO.setUid(CodeUtil.generateUserUID()); uid = CodeUtil.generateUserUID();
userAccountDO.setUid(uid);
userAccountDO.setAccountType(0); userAccountDO.setAccountType(0);
userAccountDO.setPortType(100); userAccountDO.setPortType(100);
userAccountDO.setSource(wxLoginVO.getSource()); userAccountDO.setSource(wxLoginVO.getSource());
...@@ -99,6 +106,13 @@ public class AuthServiceImpl implements AuthService { ...@@ -99,6 +106,13 @@ public class AuthServiceImpl implements AuthService {
map.put(JwtConstant.TOKEN_TYPE, JwtConstant.IUAV_TOKEN); map.put(JwtConstant.TOKEN_TYPE, JwtConstant.IUAV_TOKEN);
String token = JwtUtil.createJwt(map); String token = JwtUtil.createJwt(map);
LoginSuccessDTO loginSuccessDTO = LoginSuccessDTO.builder().token(token).userAccountId(userAccountVO.getId()).accountNo(userAccountVO.getAccountNo()).uid(uid)
.userName(userAccountVO.getUserName()).nickName(userAccountVO.getNickName()).phoneNum(userAccountVO.getPhoneNum()).build();
stringRedisTemplate.opsForValue().set(
token, JSONObject.toJSONString(loginSuccessDTO),
JwtConstant.EXPIRATION, TimeUnit.MILLISECONDS);
return ResultBody.success(AppUserSucVO.builder().token(token).uid(userAccountVO.getUid()).phoneNum(userAccountVO.getPhoneNum()) return ResultBody.success(AppUserSucVO.builder().token(token).uid(userAccountVO.getUid()).phoneNum(userAccountVO.getPhoneNum())
.nickName(userAccountVO.getNickName()).userAccountId(userAccountVO.getId()).sessionKey(sessionKey).build()); .nickName(userAccountVO.getNickName()).userAccountId(userAccountVO.getId()).sessionKey(sessionKey).build());
} }
...@@ -107,6 +121,7 @@ public class AuthServiceImpl implements AuthService { ...@@ -107,6 +121,7 @@ public class AuthServiceImpl implements AuthService {
public ResultBody backEndLogin(LoginUserQO param) { public ResultBody backEndLogin(LoginUserQO param) {
//查询用户信息 //查询用户信息
UserAccountDO user = userAccountService.getUserLoginInfo(param.getAccountNo(), param.getPassWord()); UserAccountDO user = userAccountService.getUserLoginInfo(param.getAccountNo(), param.getPassWord());
System.out.println("login user:---------------->" + user.toString() );
if (user == null) { if (user == null) {
return ResultBody.error(ResultEnum.LOGIN_ACCOUNT_NOT_EXIT_ERROR); return ResultBody.error(ResultEnum.LOGIN_ACCOUNT_NOT_EXIT_ERROR);
} }
...@@ -128,6 +143,11 @@ public class AuthServiceImpl implements AuthService { ...@@ -128,6 +143,11 @@ public class AuthServiceImpl implements AuthService {
//map.put(JwtConstant.ROLE_ID, 0); //map.put(JwtConstant.ROLE_ID, 0);
map.put(JwtConstant.TOKEN_TYPE, JwtConstant.M_TOKEN); map.put(JwtConstant.TOKEN_TYPE, JwtConstant.M_TOKEN);
String token = JwtUtil.createJwt(map); String token = JwtUtil.createJwt(map);
LoginSuccessDTO loginSuccessDTO = LoginSuccessDTO.builder().token(token).userAccountId(user.getId()).accountNo(user.getAccountNo()).uid(user.getUid())
.userName(user.getUserName()).nickName(user.getNickName()).phoneNum(user.getPhoneNum()).build();
stringRedisTemplate.opsForValue().set(
token, JSONObject.toJSONString(loginSuccessDTO),
JwtConstant.EXPIRATION, TimeUnit.MILLISECONDS);
return ResultBody.success(LoginSuccessDTO.builder().token(token).userAccountId(user.getId()).accountNo(user.getAccountNo()).build()); return ResultBody.success(LoginSuccessDTO.builder().token(token).userAccountId(user.getId()).accountNo(user.getAccountNo()).build());
} }
...@@ -140,10 +160,15 @@ public class AuthServiceImpl implements AuthService { ...@@ -140,10 +160,15 @@ public class AuthServiceImpl implements AuthService {
map.put(JwtConstant.USER_ACCOUNT_ID, userAccountVO.getId()); map.put(JwtConstant.USER_ACCOUNT_ID, userAccountVO.getId());
map.put(JwtConstant.TOKEN_TYPE, JwtConstant.IUAV_TOKEN); map.put(JwtConstant.TOKEN_TYPE, JwtConstant.IUAV_TOKEN);
String token = JwtUtil.createJwt(map); String token = JwtUtil.createJwt(map);
LoginSuccessDTO loginSuccessDTO = LoginSuccessDTO.builder().token(token).userAccountId(userAccountVO.getId()).accountNo(userAccountVO.getAccountNo()).uid(userAccountVO.getUid())
.userName(userAccountVO.getUserName()).nickName(userAccountVO.getNickName()).phoneNum(userAccountVO.getPhoneNum()).build();
stringRedisTemplate.opsForValue().set(
token, JSONObject.toJSONString(loginSuccessDTO),
JwtConstant.EXPIRATION, TimeUnit.MILLISECONDS);
return ResultBody.success(AppUserSucVO.builder().token(token).uid(userAccountVO.getUid()).phoneNum(userAccountVO.getPhoneNum()) return ResultBody.success(AppUserSucVO.builder().token(token).uid(userAccountVO.getUid()).phoneNum(userAccountVO.getPhoneNum())
.nickName(userAccountVO.getNickName()).userAccountId(userAccountVO.getId()).build()); .nickName(userAccountVO.getNickName()).userAccountId(userAccountVO.getId()).build());
} }
return null; return ResultBody.error(ResultEnum.APPLET_LOGIN_ERROR);
} }
} }
package com.mmc.iuav.user.service.impl; package com.mmc.iuav.user.service.impl;
import com.mmc.iuav.auth.JwtConstant;
import com.mmc.iuav.general.CodeUtil; import com.mmc.iuav.general.CodeUtil;
import com.mmc.iuav.page.PageResult; import com.mmc.iuav.page.PageResult;
import com.mmc.iuav.response.ResultBody; import com.mmc.iuav.response.ResultBody;
import com.mmc.iuav.response.ResultEnum; import com.mmc.iuav.response.ResultEnum;
import com.mmc.iuav.user.auth.PwdUtil; import com.mmc.iuav.user.auth.PwdUtil;
import com.mmc.iuav.user.constant.UserSystemConstant;
import com.mmc.iuav.user.dao.CooperationDao; import com.mmc.iuav.user.dao.CooperationDao;
import com.mmc.iuav.user.dao.UserServiceDao; import com.mmc.iuav.user.dao.UserServiceDao;
import com.mmc.iuav.user.entity.UserAccountDO; import com.mmc.iuav.user.entity.UserAccountDO;
...@@ -18,9 +16,10 @@ import com.mmc.iuav.user.model.vo.CompanyAuthVO; ...@@ -18,9 +16,10 @@ import com.mmc.iuav.user.model.vo.CompanyAuthVO;
import com.mmc.iuav.user.model.vo.UserAccountVO; import com.mmc.iuav.user.model.vo.UserAccountVO;
import com.mmc.iuav.user.service.CompanyAuthService; import com.mmc.iuav.user.service.CompanyAuthService;
import com.mmc.iuav.user.service.UserAccountService; import com.mmc.iuav.user.service.UserAccountService;
import com.mmc.iuav.user.service.WxService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.List; import java.util.List;
...@@ -42,6 +41,9 @@ public class UserAccountServiceImpl implements UserAccountService { ...@@ -42,6 +41,9 @@ public class UserAccountServiceImpl implements UserAccountService {
@Autowired @Autowired
private CooperationDao cooperationDao; private CooperationDao cooperationDao;
@Autowired
private WxService wxService;
@Override @Override
public UserAccountVO getUserAccountInfoByUnionId(String unionId) { public UserAccountVO getUserAccountInfoByUnionId(String unionId) {
UserAccountDO userAccountDO = userServiceDao.getUserAccountInfoByUnionId(unionId); UserAccountDO userAccountDO = userServiceDao.getUserAccountInfoByUnionId(unionId);
...@@ -162,6 +164,9 @@ public class UserAccountServiceImpl implements UserAccountService { ...@@ -162,6 +164,9 @@ public class UserAccountServiceImpl implements UserAccountService {
@Override @Override
public List<UserAccountSimpleDTO> feignListBAccountPage(BUserAccountQO bUserAccountQO) { public List<UserAccountSimpleDTO> feignListBAccountPage(BUserAccountQO bUserAccountQO) {
List<UserAccountDO> list = userServiceDao.feignListBAccountPage(bUserAccountQO); List<UserAccountDO> list = userServiceDao.feignListBAccountPage(bUserAccountQO);
if (list == null) {
return null;
}
List<UserAccountSimpleDTO> accountSimpleDTOS = list.stream().map(UserAccountDO::buildUserAccountSimpleDTO).collect(Collectors.toList()); List<UserAccountSimpleDTO> accountSimpleDTOS = list.stream().map(UserAccountDO::buildUserAccountSimpleDTO).collect(Collectors.toList());
return accountSimpleDTOS; return accountSimpleDTOS;
} }
...@@ -214,4 +219,18 @@ public class UserAccountServiceImpl implements UserAccountService { ...@@ -214,4 +219,18 @@ public class UserAccountServiceImpl implements UserAccountService {
} }
return ResultBody.success(); return ResultBody.success();
} }
@Override
public ResultBody getUserPhoneNumber(Integer id, String code) {
String userPhoneNumber = wxService.getUserPhoneNumber(id, code);
if (StringUtils.isBlank(userPhoneNumber)){
return ResultBody.error(ResultEnum.AUTH_PHONE_NUMBER_ERROR);
}
System.out.println("userPhoneNumber:"+userPhoneNumber);
UserAccountDO userAccount = new UserAccountDO();
userAccount.setId(id);
userAccount.setPhoneNum(userPhoneNumber);
userServiceDao.update(userAccount);
return ResultBody.success();
}
} }
...@@ -64,11 +64,11 @@ public class WxServiceImpl implements WxService { ...@@ -64,11 +64,11 @@ public class WxServiceImpl implements WxService {
String accessToken = stringRedisTemplate.opsForValue().get(WxConstant.IUAV_MINI_PROGRAM_ACCESS_TOKEN); String accessToken = stringRedisTemplate.opsForValue().get(WxConstant.IUAV_MINI_PROGRAM_ACCESS_TOKEN);
if (StringUtils.isBlank(accessToken)){ if (StringUtils.isBlank(accessToken)){
String getAccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token" + "?grant_type=client_credential" + "&appid=" + String getAccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token" + "?grant_type=client_credential" + "&appid=" +
userSystemConstant.getWxAppId() + "&secret" + userSystemConstant.getWxAppSecret(); userSystemConstant.getWxAppId() + "&secret=" + userSystemConstant.getWxAppSecret();
String accessTokenMsg = HttpsRequestUtil.httpsGet(getAccessTokenUrl, null); String accessTokenMsg = HttpsRequestUtil.httpsGet(getAccessTokenUrl, null);
JSONObject tokenResult = JSONObject.parseObject(accessTokenMsg); JSONObject tokenResult = JSONObject.parseObject(accessTokenMsg);
if (accessTokenMsg.indexOf("access_token") == -1) { if (accessTokenMsg.indexOf("access_token") == -1) {
System.out.println("获取用户信息有误:access_token请求失败:" + tokenResult); System.out.println("获取小程序access_token有误:" + tokenResult);
return null; return null;
} }
accessToken = tokenResult.getString("access_token"); accessToken = tokenResult.getString("access_token");
...@@ -86,11 +86,11 @@ public class WxServiceImpl implements WxService { ...@@ -86,11 +86,11 @@ public class WxServiceImpl implements WxService {
String accessToken = stringRedisTemplate.opsForValue().get(WxConstant.SHARE_FLY_SUB_ACCESS_TOKEN); String accessToken = stringRedisTemplate.opsForValue().get(WxConstant.SHARE_FLY_SUB_ACCESS_TOKEN);
if (StringUtils.isBlank(accessToken)){ if (StringUtils.isBlank(accessToken)){
String getAccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token" + "?grant_type=client_credential" + "&appid=" + String getAccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token" + "?grant_type=client_credential" + "&appid=" +
userSystemConstant.getWxSubAppId() + "&secret" + userSystemConstant.getWxSubSecret(); userSystemConstant.getWxSubAppId() + "&secret=" + userSystemConstant.getWxSubSecret();
String accessTokenMsg = HttpsRequestUtil.httpsGet(getAccessTokenUrl, null); String accessTokenMsg = HttpsRequestUtil.httpsGet(getAccessTokenUrl, null);
JSONObject tokenResult = JSONObject.parseObject(accessTokenMsg); JSONObject tokenResult = JSONObject.parseObject(accessTokenMsg);
if (accessTokenMsg.indexOf("access_token") == -1) { if (accessTokenMsg.indexOf("access_token") == -1) {
System.out.println("获取用户信息有误:access_token请求失败:" + tokenResult); System.out.println("获取公众号access_token有误:" + tokenResult);
return null; return null;
} }
accessToken = tokenResult.getString("access_token"); accessToken = tokenResult.getString("access_token");
...@@ -218,9 +218,11 @@ public class WxServiceImpl implements WxService { ...@@ -218,9 +218,11 @@ public class WxServiceImpl implements WxService {
param.put("scene", scene); param.put("scene", scene);
param.put("page", path); param.put("page", path);
param.put("width", 430); param.put("width", 430);
param.put("check_path", false);
param.put("env_version", userSystemConstant.getEnvVersion()); param.put("env_version", userSystemConstant.getEnvVersion());
String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken; String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken;
base64 = HttpHelper.httpPost(url, param.toJSONString()); //base64 = HttpHelper.httpPost(url, param.toJSONString());
base64 = HttpsRequestUtil.getACodeBase64(url, "POST", null, param.toJSONString());
return ResultBody.success(base64); return ResultBody.success(base64);
} catch (Exception e) { } catch (Exception e) {
return ResultBody.error(ResultEnum.APPLET_QR_CODE_CREATE_ERROR); return ResultBody.error(ResultEnum.APPLET_QR_CODE_CREATE_ERROR);
...@@ -268,4 +270,25 @@ public class WxServiceImpl implements WxService { ...@@ -268,4 +270,25 @@ public class WxServiceImpl implements WxService {
} }
return null; return null;
} }
@Override
public String getUserPhoneNumber(Integer id, String code) {
try {
String accessToken = this.getAccessToken();
JSONObject param = new JSONObject();
param.put("code", code);
String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken;
String res = HttpHelper.httpPost(url, param.toString());
JSONObject result = JSONObject.parseObject(res);
System.out.println("用户授权手机号:" + res);
if (result.getString("errcode").equals("0")) {
String phone_info = result.getString("phone_info");
JSONObject phoneInfoObject = JSONObject.parseObject(phone_info);
return phoneInfoObject.getString("purePhoneNumber");
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
} }
package com.mmc.iuav.user.util;
import org.springframework.util.AntPathMatcher;
/**
* @author 作者 geDuo
* @version 创建时间:2021年8月31日 下午3:29:28
* @explain 解析地址类
*/
public class PathUtil {
private static AntPathMatcher matcher = new AntPathMatcher();
public static boolean isPathMatch(String pattern, String path) {
return matcher.match(pattern, path);
}
}
server:
port: 35150
servlet:
context-path: /userapp
#spring #spring
spring: spring:
application:
name: userapp
#Database #Database
datasource: datasource:
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
...@@ -42,22 +36,12 @@ spring: ...@@ -42,22 +36,12 @@ spring:
# enabled: true # enabled: true
# login-username: druid # login-username: druid
# login-password: druid # login-password: druid
jackson:
date-format: yyyy-MM-dd HH:mm:ss
redis: redis:
database: 1 database: 1
host: r-wz9ke310fs684hacn1pd.redis.rds.aliyuncs.com host: r-wz9ke310fs684hacn1pd.redis.rds.aliyuncs.com
password: MMC@2022&REDIS password: MMC@2022&REDIS
port: 6379 port: 6379
#mybatis
mybatis:
executor-type: simple
mapper-locations: classpath:mapper/**/*.xml
type-aliases-package: com.mmc.iuav.user.entity
configuration:
map-underscore-to-camel-case: true
wx: wx:
sub: sub:
appid: wx5c6a105a0ddca4c5 appid: wx5c6a105a0ddca4c5
......
server:
port: 35150
servlet:
context-path: /userapp
#spring #spring
spring: spring:
application:
name: userapp
#Database #Database
datasource: datasource:
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
...@@ -19,16 +13,6 @@ spring: ...@@ -19,16 +13,6 @@ spring:
host: r-wz9ke310fs684hacn1pd.redis.rds.aliyuncs.com host: r-wz9ke310fs684hacn1pd.redis.rds.aliyuncs.com
password: MMC@2022&REDIS password: MMC@2022&REDIS
port: 6379 port: 6379
jackson:
date-format: yyyy-MM-dd HH:mm:ss
#mybatis
mybatis:
executor-type: simple
mapper-locations: classpath:mapper/**/*.xml
type-aliases-package: com.mmc.iuav.user
configuration:
map-underscore-to-camel-case: true
wx: wx:
sub: sub:
......
server:
port: 35150
servlet:
context-path: /userapp
#spring #spring
spring: spring:
application:
name: userapp
#Database #Database
datasource: datasource:
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
...@@ -42,22 +36,12 @@ spring: ...@@ -42,22 +36,12 @@ spring:
# enabled: true # enabled: true
# login-username: druid # login-username: druid
# login-password: druid # login-password: druid
jackson:
date-format: yyyy-MM-dd HH:mm:ss
redis: redis:
database: 1 database: 1
host: r-wz9ke310fs684hacn1pd.redis.rds.aliyuncs.com host: r-wz9ke310fs684hacn1pd.redis.rds.aliyuncs.com
password: MMC@2022&REDIS password: MMC@2022&REDIS
port: 6379 port: 6379
#mybatis
mybatis:
executor-type: simple
mapper-locations: classpath:mapper/**/*.xml
type-aliases-package: com.mmc.iuav.user
configuration:
map-underscore-to-camel-case: true
wx: wx:
sub: sub:
appid: wx5c6a105a0ddca4c5 appid: wx5c6a105a0ddca4c5
......
server:
port: 35150
servlet:
context-path: /userapp
spring: spring:
profiles: profiles:
active: local active: local
application:
name: userapp
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
#mybatis
mybatis:
executor-type: simple
mapper-locations: classpath:mapper/**/*.xml
type-aliases-package: com.mmc.iuav.user
configuration:
map-underscore-to-camel-case: true
--- ---
spring: spring:
......
...@@ -119,7 +119,9 @@ ...@@ -119,7 +119,9 @@
<select id="getUserLoginInfo" resultType="com.mmc.iuav.user.entity.UserAccountDO"> <select id="getUserLoginInfo" resultType="com.mmc.iuav.user.entity.UserAccountDO">
select ua.id, select ua.id,
ua.uid,
ua.account_no, ua.account_no,
ua.phone_num,
ua.pass_word, ua.pass_word,
ua.account_status, ua.account_status,
ua.account_type, ua.account_type,
...@@ -130,23 +132,23 @@ ...@@ -130,23 +132,23 @@
</select> </select>
<select id="feignListBAccountPage" resultType="com.mmc.iuav.user.entity.UserAccountDO" parameterType="com.mmc.iuav.user.model.qo.BUserAccountQO"> <select id="feignListBAccountPage" resultType="com.mmc.iuav.user.entity.UserAccountDO" parameterType="com.mmc.iuav.user.model.qo.BUserAccountQO">
select id, account_type, account_no, uid, phone_num, user_name, nick_name, user_img, open_id, union_id, user_sex, email, source, account_status, remark, select ua.id, ua.account_type, ua.account_no, ua.uid, ua.phone_num, ua.user_name, ua.nick_name, ua.user_img, ua.open_id, ua.union_id, ua.user_sex, ua.email, ua.source, ua.account_status, ua.remark,
port_type, is_deleted as deleted, create_time, update_time ua.port_type, ua.is_deleted as deleted, ua.create_time, ua.update_time, ut.cooperation_tag_id, ca.auth_status as companyAuthStatus
from user_account from user_account ua left join user_tag ut on ua.id = ut.user_account_id left join company_auth ca on ua.id = ca.user_account_id
where is_deleted = 0 and port_type = 0 where ua.is_deleted = 0
<if test=" userIds != null "> <if test=" userIds != null ">
<foreach collection="userIds" item="id" open="and id in (" close=")" separator=","> <foreach collection="userIds" item="id" open="and ua.id in (" close=")" separator=",">
#{id} #{id}
</foreach> </foreach>
</if> </if>
<if test="provinceCode != null"> <if test="provinceCode != null">
and province_code = #{provinceCode} and ua.province_code = #{provinceCode}
</if> </if>
<if test="cityCode != null"> <if test="cityCode != null">
and city_code = #{cityCode} and ua.city_code = #{cityCode}
</if> </if>
<if test="districtCode != null"> <if test="districtCode != null">
and district_code = #{districtCode} and ua.district_code = #{districtCode}
</if> </if>
</select> </select>
......
data-filter:
uploadPath: #不需要解析的body参数的地址
- /xxx/x
not-auth-path:
- /userapp/v2/**
- /userapp/doc.html
- /userapp/swagger-resources/**
- /userapp/webjars/**
- /userapp/auth/testAppletLogin
- /userapp/auth/backEndLogin
- /userapp/auth/testAppletLogin
- /userapp/cooperation/listTag
...@@ -17,4 +17,4 @@ patches: ...@@ -17,4 +17,4 @@ patches:
images: images:
- name: REGISTRY/NAMESPACE/IMAGE:TAG - name: REGISTRY/NAMESPACE/IMAGE:TAG
newName: mmc-registry.cn-shenzhen.cr.aliyuncs.com/sharefly-dev/cms newName: mmc-registry.cn-shenzhen.cr.aliyuncs.com/sharefly-dev/cms
newTag: 2df3064ac9fa8f9c581b6bc6c7df63695693dee5 newTag: c4c184f6677536af1d4693f7fbcf5eb6b9784947
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论