Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
王奎兴
2026-07-09 16:00:24 +08:00
19 changed files with 399 additions and 15 deletions
@@ -18,7 +18,7 @@ import java.util.Set;
/**
* bms财务结算系统feign调用接口
*/
@FeignClient(contextId = "BmsService", value = ServiceNameConstants.BMS_SERVICE, url = "http://10.102.192.32:8019",fallbackFactory = RemoteBmsFeignFallbackFactory.class, configuration = FeignAutoConfiguration.class)
@FeignClient(contextId = "BmsService", value = ServiceNameConstants.BMS_SERVICE, url = "http://10.102.192.3:8019",fallbackFactory = RemoteBmsFeignFallbackFactory.class, configuration = FeignAutoConfiguration.class)
public interface BmsServiceFeign {
@@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@FeignClient(contextId = "OmsService", value = ServiceNameConstants.OMS_SERVICE,url = "http://10.102.192.33", fallbackFactory = RemoteOmsFeignFallbackFactory.class, configuration = FeignAutoConfiguration.class)
@FeignClient(contextId = "OmsService", value = ServiceNameConstants.OMS_SERVICE,url = "http://10.102.192.4:8017", fallbackFactory = RemoteOmsFeignFallbackFactory.class, configuration = FeignAutoConfiguration.class)
public interface OmsServiceFeign {
@@ -223,4 +223,7 @@ public interface UserServiceFeign {
@ApiOperation("查询赊销额度")
@PostMapping("/userShipperApi/querySaleCreditLimitFeign")
public AjaxResult querySaleCreditLimitFeign(@RequestBody UserShipperFeignDTO userShipperDTO);
@GetMapping("/userApi/getUserByUserAccount")
R<LoginUser> getUserByUserAccount(@RequestParam("userAccount") String account);
}
@@ -26,7 +26,7 @@ import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@FeignClient(contextId = "commonWlhyServiceFeign",value = ServiceNameConstants.WLHY_SERVICE,url = "http://10.102.192.31:8014",configuration = FeignAutoConfiguration.class)
@FeignClient(contextId = "commonWlhyServiceFeign",value = ServiceNameConstants.WLHY_SERVICE,url = "http://10.102.192.30:8014",configuration = FeignAutoConfiguration.class)
public interface WlhyServiceFeign {
/**
@@ -21,7 +21,7 @@ import java.util.Map;
* @description: TODO
* @date 2024/5/10 8:58
**/
@FeignClient(contextId = "remoteWmsServiceFeign",value = ServiceNameConstants.WMS_SERVICE, url = "http://10.102.192.32:8016", fallbackFactory = RemoteWmsFallbackFactory.class, configuration = FeignAutoConfiguration.class)
@FeignClient(contextId = "remoteWmsServiceFeign",value = ServiceNameConstants.WMS_SERVICE, url = "http://10.102.192.3:8016", fallbackFactory = RemoteWmsFallbackFactory.class, configuration = FeignAutoConfiguration.class)
public interface WmsServiceFeign {
/**
@@ -9,7 +9,7 @@ import com.mhd.system.api.feign.FeignAutoConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
@FeignClient(contextId = "YmsService", value = ServiceNameConstants.YMS_SERVICE,fallbackFactory = RemoteBmsFeignFallbackFactory.class,url = "http://10.102.192.33:8018", configuration = FeignAutoConfiguration.class)
@FeignClient(contextId = "YmsService", value = ServiceNameConstants.YMS_SERVICE,fallbackFactory = RemoteBmsFeignFallbackFactory.class,url = "http://10.102.192.4:8018", configuration = FeignAutoConfiguration.class)
public interface YmsServiceFeign {
/**
@@ -170,6 +170,11 @@ public class RemoteUserFeignFallbackFactory implements FallbackFactory<UserServi
return R.fail("获取组织用户失败:" + throwable.getMessage());
}
@Override
public R<LoginUser> getUserByUserAccount(String userAccount) {
return R.fail("获取用户失败:" + throwable.getMessage());
}
@Override
public R<LoginUser> getUserByTopOrganizationUserPhone(@RequestBody UserDTO userDTO, String source) {
return R.fail("获取组织用户失败:" + throwable.getMessage());
@@ -0,0 +1,89 @@
package com.mhd.auth.system.controller;
import com.mhd.auth.system.service.SsoAuthorizeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
* SSO单点登录控制器
* 子系统端实现:接收中台传递的签名参数,验签后自动登录并重定向
*
* @author mhd
*/
@Slf4j
@RestController
@RequestMapping("/auth")
@CrossOrigin
public class SsoAuthorizeController {
@Autowired
private SsoAuthorizeService ssoAuthorizeService;
/**
* SSO单点登录授权接口
* 中台点击子系统链接后,将签名参数传递给此接口
* 验签通过后自动登录并重定向到前端页面,携带token
*
* @param signature 签名信息(Base64编码后再URL编码),签名源数据格式:appkey=xxx&account=xxx&timestamp=xxxxxx
* @param appkey 对方的应用key,值固定为nanguang
* @param account 账号
* @param timestamp 当前时间戳(毫秒),用于防止签名被盗用,超过24小时视为失效
*/
@GetMapping("/sso-authorize")
public void ssoAuthorize(@RequestParam("signature") String signature,
@RequestParam("appkey") String appkey,
@RequestParam("account") String account,
@RequestParam("timestamp") Long timestamp,
HttpServletResponse response) throws IOException {
log.info("SSO单点登录请求, appkey={}, account={}, timestamp={}", appkey, account, timestamp);
String redirectUrl = ssoAuthorizeService.getRedirectUrl();
try {
// 1. 校验时间戳是否超过24小时,防止签名被盗用
long ONE_DAY_MILLIS = 24L * 60 * 60 * 1000;
long currentTime = System.currentTimeMillis();
if ((currentTime - timestamp) > ONE_DAY_MILLIS) {
log.warn("SSO签名已过期, appkey={}, account={}, timestamp={}, 距今{}小时",
appkey, account, timestamp, (currentTime - timestamp) / (60 * 60 * 1000));
response.sendRedirect(redirectUrl + "?msg=" + URLEncoder.encode("登录失败:签名已超过24小时,请重新发起", StandardCharsets.UTF_8.name()));
return;
}
// 2. 构造签名源数据(包含timestamp)
String sourceData = "appkey=" + appkey + "&account=" + account + "&timestamp=" + timestamp;
// 3. 验证签名
boolean verifyResult = ssoAuthorizeService.verifySignature(sourceData, signature);
if (!verifyResult) {
log.warn("SSO验签失败, appkey={}, account={}, timestamp={}", appkey, account, timestamp);
response.sendRedirect(redirectUrl + "?msg=" + URLEncoder.encode("登录失败:签名验证不通过", StandardCharsets.UTF_8.name()));
return;
}
// 4. 验签通过,使用account进行登录,获取token
Map<String, Object> loginResult = ssoAuthorizeService.ssoLogin(account);
String accessToken = (String) loginResult.get("access_token");
// 5. 重定向到前端页面,token通过URL参数传递
// 前端页面需读取URL中的token参数并存入localStorage
log.info("SSO单点登录成功, account={}", account);
response.sendRedirect(redirectUrl + "?token=" + URLEncoder.encode(accessToken, StandardCharsets.UTF_8.name()));
} catch (Exception e) {
log.error("SSO单点登录异常, appkey={}, account={}, timestamp={}", appkey, account, timestamp, e);
response.sendRedirect(redirectUrl + "?msg=" + URLEncoder.encode("登录失败:" + e.getMessage(), StandardCharsets.UTF_8.name()));
}
}
}
@@ -0,0 +1,200 @@
package com.mhd.auth.system.service;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.mhd.common.core.constant.CacheConstants;
import com.mhd.common.core.constant.Constants;
import com.mhd.common.core.constant.SecurityConstants;
import com.mhd.common.core.domain.entity.R;
import com.mhd.common.core.domain.po.OrganizationPo;
import com.mhd.common.core.domain.po.RolePO;
import com.mhd.common.core.domain.po.UserPo;
import com.mhd.common.core.enums.UserStatus;
import com.mhd.common.core.exception.ServiceException;
import com.mhd.common.core.utils.ServletUtils;
import com.mhd.common.core.utils.ip.IpUtil;
import com.mhd.common.core.utils.ip.IpUtils;
import com.mhd.common.core.web.domain.AjaxResult;
import com.mhd.common.log.service.AsyncLogService;
import com.mhd.common.security.service.TokenService;
import com.mhd.system.api.SystemServiceFeign;
import com.mhd.system.api.UserServiceFeign;
import com.mhd.system.api.domain.UserDTO;
import com.mhd.system.api.domain.UserUpdateDTO;
import com.mhd.system.api.model.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.util.Base64;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* SSO单点登录服务
*
* @author mhd
*/
@Slf4j
@Service
public class SsoAuthorizeService {
@Value("${sso.public-key}")
private String publicKeyStr;
@Value("https://diglog.namkwong.com.mo/main_app/sso")
private String redirectUrl;
@Resource
private UserServiceFeign userServiceFeign;
@Resource
private TokenService tokenService;
@Autowired
private AsyncLogService asyncLogService;
@Autowired
private SystemServiceFeign systemServiceFeign;
@Resource
private com.mhd.auth.app.infrastructure.feign.OrganizationServiceFeign organizationServiceFeign;
/**
* 验证RSA签名
*
* @param sourceData 签名源数据,格式:appkey=xxx&account=xxx&timestamp=xxxxxx
* @param signatureStr Base64编码的签名(可能经过URL编码)
* @return 验签结果
*/
public boolean verifySignature(String sourceData, String signatureStr) {
try {
// Spring @RequestParam 已自动完成 URL 解码,此处直接 Base64 解码即可
byte[] signatureBytes = Base64.getDecoder().decode(signatureStr);
PublicKey publicKey = generatePublicKey(publicKeyStr);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(publicKey);
signature.update(sourceData.getBytes("UTF-8"));
return signature.verify(signatureBytes);
} catch (Exception e) {
log.error("SSO验签失败, sourceData={}, signature={}", sourceData, signatureStr, e);
return false;
}
}
/**
* 根据公钥字符串生成PublicKey对象
*/
private PublicKey generatePublicKey(String keyStr) throws Exception {
// 去除头尾标记和空白字符
String publicKeyContent = keyStr
.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
.replaceAll("\\s+", "");
byte[] keyBytes = Base64.getDecoder().decode(publicKeyContent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
java.security.spec.X509EncodedKeySpec keySpec = new java.security.spec.X509EncodedKeySpec(keyBytes);
return keyFactory.generatePublic(keySpec);
}
/**
* SSO登录:根据account查找用户并创建token
*
* @param account 账号
* @return 包含token等信息的Map
*/
public Map<String, Object> ssoLogin(String account) {
// 根据账号查找用户(SSO登录不区分组织,仅通过userAccount查询)
R<LoginUser> userResult = userServiceFeign.getUserByUserAccount(account);
if (R.FAIL == userResult.getCode()) {
throw new ServiceException(userResult.getMsg());
}
if (userResult.getData() == null) {
throw new ServiceException("SSO登录用户不存在:" + account);
}
LoginUser userInfo = userResult.getData();
UserPo userPo = userInfo.getUserPo();
// 校验用户状态
if (userPo == null) {
throw new ServiceException("SSO登录用户信息异常:" + account);
}
// 删除标记
if (UserStatus.DELETED.getCode().equals(String.valueOf(userPo.getDelFlag()))) {
throw new ServiceException("对不起,您的账号:" + account + " 已被删除");
}
// 用户状态
if (UserStatus.DELETED.getCode().equals(String.valueOf(userPo.getUserStatus()))) {
throw new ServiceException("对不起,您的账号:" + account + " 已停用");
}
// 获取组织信息
com.mhd.common.core.domain.entity.R<OrganizationPo> organizationInfo = organizationServiceFeign.getInfoForIdList(userPo.getOrganizationId());
if (ObjectUtil.isNull(organizationInfo) || ObjectUtil.isNull(organizationInfo.getData())) {
throw new ServiceException("登录用户组织不存在");
}
userInfo.setOrganizationPo(organizationInfo.getData());
// 查询用户角色
AjaxResult roleListAjaxResult = userServiceFeign.getRoleListByUserId(userPo.getUserId());
if ("200".equals(String.valueOf(roleListAjaxResult.get("code"))) && ObjectUtil.isNotNull(roleListAjaxResult.get("data"))) {
List<RolePO> rolePOS = JSONUtil.toList(JSONUtil.toJsonStr(roleListAjaxResult.get("data")), RolePO.class);
if (rolePOS != null && !rolePOS.isEmpty()) {
userInfo.setRoleList(rolePOS.stream().map(RolePO::getRoleName).collect(Collectors.toList()));
userInfo.setRoleIdList(rolePOS.stream().map(RolePO::getRoleId).collect(Collectors.toList()));
}
}
// 更新登录信息
UserUpdateDTO userUpdateDTO = new UserUpdateDTO();
userUpdateDTO.setLastLoginTime(new Date());
userUpdateDTO.setLastLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
userUpdateDTO.setUserName(account);
userServiceFeign.updateWhenLogin(userUpdateDTO, SecurityConstants.INNER);
// 创建token
Map<String, Object> result = tokenService.createTokenApi(userInfo);
// 记录登录日志
recordLogininfor(userPo, Constants.LOGIN_SUCCESS, "SSO单点登录成功", 1);
return result;
}
/**
* 记录登录信息
*/
private void recordLogininfor(UserPo userPo, String status, String message, Integer behaviorType) {
com.mhd.system.api.domain.SysLogininforPo logininfor = new com.mhd.system.api.domain.SysLogininforPo();
logininfor.setUserAccount(userPo.getUserAccount());
logininfor.setUserName(userPo.getUserName());
logininfor.setIpaddr(IpUtils.getIpAddr(ServletUtils.getRequest()));
logininfor.setLocation(StrUtil.isNotEmpty(logininfor.getIpaddr()) ? IpUtil.getLocationSplicing(logininfor.getIpaddr()) : "");
logininfor.setBehaviorType(behaviorType);
logininfor.setMsg(message);
logininfor.setOrganizationId(userPo.getOrganizationId());
logininfor.setOrganizationName(userPo.getOrganizationName());
logininfor.setTopOrganizationId(userPo.getTopOrganizationId());
logininfor.setAccessTime(cn.hutool.core.date.DateUtil.date());
if (org.apache.commons.lang3.StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) {
logininfor.setStatus(Constants.LOGIN_SUCCESS_STATUS);
} else if (Constants.LOGIN_FAIL.equals(status)) {
logininfor.setStatus(Constants.LOGIN_FAIL_STATUS);
}
asyncLogService.saveLogininfor(logininfor);
}
public String getRedirectUrl() {
return redirectUrl;
}
}
+23 -6
View File
@@ -15,19 +15,20 @@ spring:
# server-addr: 127.0.0.1:8848
# 线上测试环境配置 容器名+端口号
# server-addr: 10.33.0.129:6010
# username: nacos
# password: manhuoda@2023
#线上正式环境
server-addr: 10.102.192.31:6848
server-addr: 10.102.192.30:6848
username: nacos
password: manhuoda@2023
#线上正式环境
# server-addr: 10.102.192.5:6848
# username: nacos
# password: manhuoda@2023
config:
# server-addr: 127.0.0.1:8848
server-addr: 10.102.192.30:6848
# 测试环境配置 容器名+端口号
# server-addr: 10.33.0.129:6010
# 线上测试环境配置 容器名+端口号
#
server-addr: 10.102.192.31:6848
# server-addr: 10.102.192.5:6848
username: nacos
password: manhuoda@2023
#线上正式环境
@@ -36,3 +37,19 @@ spring:
# 共享配置
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
# SSO单点登录配置
sso:
# RSA公钥(由中台openssl私钥导出)
public-key: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA62dYkl2Nvy2wW9028dQ7
HdxFNhwEriFNzFMFq+m1jTvZWdU6e9a1iCGWTVV2fTo4PWSyhjWyzv2ZBEuanWBq
y/bfh/jOTjT/tlWvMeJZ1TV4suCbigHq5TGxDsY6ZC6if9ULhU3NWkgnPNn6HfO9
NVvBTfx9MgWtCtT33kq30KgxC6LqVdCe08+gD0KB3df0DK8OJorVFfxYVc7TjGEL
xqUuE7PcgZgDb8KvdgO66OxBqFIB0qfc73oALKGoq/8kvjrqE/amaIZPv3jE2Rc7
0rIhGHrFcoA3W01nNRGQKY/E/VKOGBn/uDNdi5iMXsFjKxiBbXB07bBxdhUH7698
AwIDAQAB
-----END PUBLIC KEY-----
# SSO登录成功后跳转的前端页面地址
redirect-url: "/"
@@ -191,6 +191,7 @@ public class AuthFilter implements GlobalFilter, Ordered
/**
* 获取请求token
* 优先从 Authorization 请求头获取,其次从 URL 参数 token 获取(SSO场景)
*/
private String getToken(ServerHttpRequest request)
{
@@ -200,6 +201,11 @@ public class AuthFilter implements GlobalFilter, Ordered
{
token = token.replaceFirst(TokenConstants.PREFIX, StringUtils.EMPTY);
}
// 兜底:从URL参数中获取token(SSO单点登录场景,前端尚未存入localStorage时)
if (StringUtils.isEmpty(token))
{
token = request.getQueryParams().getFirst("token");
}
return token;
}
@@ -2942,6 +2942,33 @@ public class UserApplicationService {
return null;
}
/**
* 仅根据用户登录账号获取用户信息不区分组织SSO等场景使用
*/
public LoginUser getUserByUserAccount(String userAccount) {
UserPo userPo = userDomainService.findByUserAccount(userAccount);
if (ObjectUtil.isNotNull(userPo)) {
LoginUser sysUser = new LoginUser();
sysUser.setUserid(userPo.getUserId());
sysUser.setUsername(userPo.getUserAccount());
UserDriverPo userDriverPo = userDriverDomainService.selectByUserId(userPo.getUserId());
UserShipperPo userShipperPo = userShipperDomainService.selectByUserId(userPo.getUserId());
sysUser.setUserPo(userPo);
com.mhd.common.core.domain.po.UserDriverPo userDriverPo1 = new com.mhd.common.core.domain.po.UserDriverPo();
if(userDriverPo != null){
BeanUtils.copyProperties(userDriverPo, userDriverPo1);
}
sysUser.setUserDriverPo(userDriverPo1);
com.mhd.common.core.domain.po.UserShipperPo userShipperPo1 = new com.mhd.common.core.domain.po.UserShipperPo();
if (userShipperPo != null){
BeanUtils.copyProperties(userShipperPo, userShipperPo1);
}
sysUser.setUserShipperPo(userShipperPo1);
return sysUser;
}
return null;
}
/**
* @Description 根据用户账号和组织账号获取组织用户信息
* @Author Alex
@@ -31,6 +31,12 @@ public interface UserRepositoryInterface extends IService<UserEntity> {
UserPo findByTopOrganizationIdAndUserAccount(UserDO userDO);
/**
* 仅根据用户登录账号查询用户(不区分组织,SSO等场景使用)
*/
UserPo findByUserAccount(String userAccount);
UserPo getUserByDingUserId(String dingUserId);
UserPo selectUserShipperList(UserPo userPo);
@@ -33,6 +33,11 @@ public interface UserMapper extends BaseMapper<UserEntity> {
UserPo findByTopOrganizationIdAndUserAccount(UserDO userDO);
/**
* 仅根据用户登录账号查询用户(不区分组织,SSO等场景使用)
*/
UserPo findByUserAccount(@Param("userAccount") String userAccount);
UserPo getUserByDingUserId(@Param("dingUserId") String dingUserId);
UserPo findByTopOrganizationIdAndUserPhone(UserDO userDO);
@@ -79,6 +79,11 @@ public class UserRepositoryImpl extends ServiceImpl<UserMapper,UserEntity> imple
return userMapper.findByTopOrganizationIdAndUserAccount(userDO);
}
@Override
public UserPo findByUserAccount(String userAccount) {
return userMapper.findByUserAccount(userAccount);
}
@Override
public UserPo getUserByDingUserId(String dingUserId) {
return userMapper.getUserByDingUserId(dingUserId);
@@ -82,6 +82,13 @@ public class UserDomainService {
return userRepositoryInterface.findByTopOrganizationIdAndUserAccount(userDO);
}
/**
* 仅根据用户登录账号查询用户(不区分组织,SSO等场景使用)
*/
public UserPo findByUserAccount(String userAccount) {
return userRepositoryInterface.findByUserAccount(userAccount);
}
public UserPo getUserByDingUserId(String dingUserId) {
return userRepositoryInterface.getUserByDingUserId(dingUserId);
}
@@ -500,6 +500,13 @@ public class UserAPI extends BaseController {
return R.ok(sysUserVo, "操作成功");
}
@ApiOperation("仅根据用户登录账号获取用户信息(不区分组织,SSO等场景)")
@GetMapping("/getUserByUserAccount")
public R<LoginUser> getUserByUserAccount(@RequestParam(value = "userAccount") String userAccount) {
LoginUser sysUserVo = userApplicationService.getUserByUserAccount(userAccount);
return R.ok(sysUserVo, "操作成功");
}
@ApiOperation("根据用户钉钉用户id获取用户信息")
@GetMapping("/getUserByDingUserId")
public R<LoginUser> getUserByDingUserId(@RequestParam(value = "dingUserId") String dingUserId) {
@@ -20,15 +20,15 @@ spring:
discovery:
# server-addr: 127.0.0.1:8848
# 线上测试环境配置 容器名+端口号
# server-addr: 10.33.0.129:6010
server-addr: 10.102.192.30:6848
server-addr: 10.33.0.129:6010
# server-addr: 10.102.192.30:6848
username: nacos
password: manhuoda@2023
config:
# server-addr: 127.0.0.1:8848
# 线上测试环境配置 容器名+端口号
# server-addr: 10.33.0.129:6010
server-addr: 10.102.192.30:6848
server-addr: 10.33.0.129:6010
# server-addr: 10.102.192.30:6848
username: nacos
password: manhuoda@2023
group: DEFAULT_GROUP # 默认分组就是DEFAULT_GROUP,如果使用默认分组可以不配置
@@ -153,6 +153,13 @@
</if>
limit 1
</select>
<!-- 仅根据用户登录账号查询用户(不区分组织,SSO等场景使用) -->
<select id="findByUserAccount" parameterType="java.lang.String"
resultType="com.mhd.common.core.domain.po.UserPo">
<include refid="selectUserVo"/>
and a.user_account = #{userAccount}
limit 1
</select>
<!-- 根据用户钉钉userID查询用户 -->
<select id="getUserByDingUserId" parameterType="java.lang.String"
resultType="com.mhd.common.core.domain.po.UserPo">