fix: 公众号登录功能同步

This commit is contained in:
ageer
2025-04-30 19:34:09 +08:00
parent cd490aa0e5
commit 5476a4b0b7
18 changed files with 609 additions and 67 deletions

10
pom.xml
View File

@@ -337,11 +337,11 @@
<version>${revision}</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.ruoyi</groupId>-->
<!-- <artifactId>ruoyi-demo</artifactId>-->
<!-- <version>${revision}</version>-->
<!-- </dependency>-->
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-wechat</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</dependencyManagement>

View File

@@ -57,6 +57,10 @@
<artifactId>ruoyi-generator</artifactId>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-wechat</artifactId>
</dependency>
</dependencies>

View File

@@ -19,12 +19,10 @@ import org.ruoyi.common.core.constant.TenantConstants;
import org.ruoyi.common.core.domain.dto.RoleDTO;
import org.ruoyi.common.core.domain.model.LoginUser;
import org.ruoyi.common.core.domain.model.VisitorLoginBody;
import org.ruoyi.common.core.domain.model.VisitorLoginUser;
import org.ruoyi.common.core.enums.*;
import org.ruoyi.common.core.exception.user.CaptchaException;
import org.ruoyi.common.core.exception.user.CaptchaExpireException;
import org.ruoyi.common.core.exception.user.UserException;
import org.ruoyi.common.core.service.ConfigService;
import org.ruoyi.common.core.utils.*;
import org.ruoyi.common.log.event.LogininforEvent;
import org.ruoyi.common.redis.utils.RedisUtils;
@@ -32,8 +30,7 @@ import org.ruoyi.common.satoken.utils.LoginHelper;
import org.ruoyi.common.tenant.exception.TenantException;
import org.ruoyi.common.tenant.helper.TenantHelper;
import org.ruoyi.system.domain.SysUser;
import org.ruoyi.system.domain.bo.SysUserBo;
import org.ruoyi.system.domain.vo.LoginVo;
import org.ruoyi.system.domain.vo.SysTenantVo;
import org.ruoyi.system.domain.vo.SysUserVo;
import org.ruoyi.system.mapper.SysUserMapper;
@@ -43,7 +40,6 @@ import org.springframework.stereotype.Service;
import java.time.Duration;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.function.Supplier;
/**
@@ -60,8 +56,6 @@ public class SysLoginService {
private final WxMaService wxMaService;
private final ISysPermissionService permissionService;
private final ISysTenantService tenantService;
private final ISysUserService userService;
private final ConfigService configService;
@Value("${user.password.maxRetryCount}")
private Integer maxRetryCount;
@@ -69,7 +63,7 @@ public class SysLoginService {
private Integer lockTime;
/**
* 获取微信
* 获取微信code
* @param xcxCode 获取xcxCode
*/
public String getOpenidFromCode(String xcxCode) {
@@ -137,9 +131,8 @@ public class SysLoginService {
return StpUtil.getTokenValue();
}
/**
* 游客登录
* 微信小程序登录
*
* @param loginBody
* @return String
@@ -164,57 +157,6 @@ public class SysLoginService {
}
}
public LoginVo mpLogin(String openid) {
// 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户
SysUserVo user = userService.selectUserByOpenId(openid);
VisitorLoginUser loginUser = new VisitorLoginUser();
if (ObjectUtil.isNull(user)) {
SysUserBo sysUser = new SysUserBo();
// 改为自增
String name = "用户" + UUID.randomUUID().toString().replace("-", "");
// 设置默认用户名
sysUser.setUserName(name);
// 设置默认昵称
sysUser.setNickName(name);
// 设置默认密码
sysUser.setPassword(BCrypt.hashpw("123456"));
// 设置微信openId
sysUser.setOpenId(openid);
String configValue = configService.getConfigValue("mail", "amount");
// 设置默认余额
sysUser.setUserBalance(NumberUtils.toDouble(configValue, 1));
// 注册用户,设置默认租户为0
SysUser registerUser = userService.registerUser(sysUser, "0");
// 构建登录用户信息
loginUser.setTenantId("0");
loginUser.setUserId(registerUser.getUserId());
loginUser.setUsername(registerUser.getUserName());
loginUser.setUserType(UserType.APP_USER.getUserType());
loginUser.setOpenid(openid);
loginUser.setNickName(registerUser.getNickName());
} else {
// 此处可根据登录用户的数据不同 自行创建 loginUser
loginUser.setTenantId(user.getTenantId());
loginUser.setUserId(user.getUserId());
loginUser.setUsername(user.getUserName());
loginUser.setUserType(user.getUserType());
loginUser.setNickName(user.getNickName());
loginUser.setAvatar(user.getWxAvatar());
loginUser.setOpenid(openid);
}
// 生成token
LoginHelper.loginByDevice(loginUser, DeviceType.XCX);
recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
LoginVo loginVo = new LoginVo();
// 生成令牌
loginVo.setToken(StpUtil.getTokenValue());
loginVo.setUserInfo(loginUser);
return loginVo;
}
/**
* 退出登录
*/

View File

@@ -23,6 +23,10 @@
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-chat-api</artifactId>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-system-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -3,12 +3,15 @@ package org.ruoyi.config;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
/**
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@Data
@ConfigurationProperties(prefix = "wechat.cp")
public class WxCpProperties {
/**
* 设置企业微信的corpId

View File

@@ -0,0 +1,48 @@
package org.ruoyi.controller;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.ruoyi.service.WeixinUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @author https://www.wdbyte.com
*/
@Slf4j
@RestController
public class WeixinServerController {
@Autowired
private WeixinUserService weixinUserService;
@GetMapping(value = "/weixin/check")
public String weixinCheck(HttpServletRequest request) {
String signature = request.getParameter("signature");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String echostr = request.getParameter("echostr");
if (StringUtils.isEmpty(signature) || StringUtils.isEmpty(timestamp) || StringUtils.isEmpty(nonce)) {
return "";
}
weixinUserService.checkSignature(signature, timestamp, nonce);
return echostr;
}
@PostMapping(value = "/weixin/check")
public String weixinMsg(@RequestBody String requestBody, @RequestParam("signature") String signature,
@RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce) {
log.debug("requestBody:{}", requestBody);
log.debug("signature:{}", signature);
log.debug("timestamp:{}", timestamp);
log.debug("nonce:{}", nonce);
weixinUserService.checkSignature(signature, timestamp, nonce);
return weixinUserService.handleWeixinMsg(requestBody);
}
}

View File

@@ -0,0 +1,52 @@
package org.ruoyi.controller;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.ruoyi.common.core.domain.R;
import org.ruoyi.domin.WeixinQrCode;
import org.ruoyi.service.VxLoginService;
import org.ruoyi.system.domain.vo.LoginVo;
import org.ruoyi.util.WeixinApiUtil;
import org.ruoyi.util.WeixinQrCodeCacheUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author https://www.wdbyte.com
*/
@Slf4j
@RestController
public class WeixinUserController {
@Autowired
private WeixinApiUtil weixinApiUtil;
@Autowired
private VxLoginService loginService;
@GetMapping(value = "/user/qrcode")
public R<WeixinQrCode> getQrCode() {
WeixinQrCode qrCode = weixinApiUtil.getQrCode();
qrCode.setUrl(null);
qrCode.setExpireSeconds(null);
return R.ok(qrCode);
}
/**
* 校验是否扫描完成
* 完成,返回 JWT
* 未完成,返回 check failed
*/
@GetMapping(value = "/user/login/qrcode")
public R<LoginVo> userLogin(String ticket) {
String openId = WeixinQrCodeCacheUtil.get(ticket);
if (StringUtils.isNotEmpty(openId)) {
log.info("login success,open id:{}", openId);
LoginVo loginVo = loginService.mpLogin(openId);
return R.ok(loginVo);
}
log.info("login error,ticket:{}", ticket);
return R.fail("check failed");
}
}

View File

@@ -1,4 +1,4 @@
package org.ruoyi.controller.wxcplogin;
package org.ruoyi.controller;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.cp.api.WxCpService;

View File

@@ -0,0 +1,58 @@
package org.ruoyi.domin;
import lombok.Data;
@Data
public class ReceiveMessage {
/**
* 开发者微信号
*/
private String toUserName;
/**
* 发送方账号(一个openid
*/
private String fromUserName;
/**
* 消息创建时间(整形)
*/
private String createTime;
/**
* 消息类型
*/
private String msgType;
/**
* 文本消息内容
*/
private String content;
/**
* 消息ID 64位
*/
String msgId;
/**
* 消息的数据ID 消息来自文章才有
*/
private String msgDataId;
/**
* 多图文时第几篇文章从1开始 消息如果来自文章才有
*/
private String idx;
/**
* 订阅事件 subscribe 订阅 unsbscribe 取消订阅
*/
private String event;
/**
* 扫码 - ticket
*/
private String ticket;
public String getReplyTextMsg(String msg) {
String xml = "<xml>\n"
+ " <ToUserName><![CDATA[" + getFromUserName() + "]]></ToUserName>\n"
+ " <FromUserName><![CDATA[" + getToUserName() + "]]></FromUserName>\n"
+ " <CreateTime>" + System.currentTimeMillis() + "</CreateTime>\n"
+ " <MsgType><![CDATA[text]]></MsgType>\n"
+ " <Content><![CDATA[" + msg + "]]></Content>\n"
+ " </xml>";
return xml;
}
}

View File

@@ -0,0 +1,15 @@
package org.ruoyi.domin;
import lombok.Data;
/**
* @author https://www.wdbyte.com
*/
@Data
public class WeixinQrCode {
private String ticket;
private Long expireSeconds;
private String url;
private String qrCodeUrl;
}

View File

@@ -0,0 +1,108 @@
package org.ruoyi.service;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils;
import org.ruoyi.common.core.constant.Constants;
import org.ruoyi.common.core.domain.model.VisitorLoginUser;
import org.ruoyi.common.core.enums.DeviceType;
import org.ruoyi.common.core.enums.UserType;
import org.ruoyi.common.core.service.ConfigService;
import org.ruoyi.common.core.utils.MessageUtils;
import org.ruoyi.common.core.utils.ServletUtils;
import org.ruoyi.common.core.utils.SpringUtils;
import org.ruoyi.common.log.event.LogininforEvent;
import org.ruoyi.common.satoken.utils.LoginHelper;
import org.ruoyi.system.domain.SysUser;
import org.ruoyi.system.domain.bo.SysUserBo;
import org.ruoyi.system.domain.vo.LoginVo;
import org.ruoyi.system.domain.vo.SysUserVo;
import org.ruoyi.system.service.ISysUserService;
import org.springframework.stereotype.Service;
import java.util.UUID;
/**
* 描述:微信公众号登录
*
* @author ageerle@163.com
* date 2025/4/30
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class VxLoginService {
private final ISysUserService userService;
private final ConfigService configService;
public LoginVo mpLogin(String openid) {
// 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户
SysUserVo user = userService.selectUserByOpenId(openid);
VisitorLoginUser loginUser = new VisitorLoginUser();
if (ObjectUtil.isNull(user)) {
SysUserBo sysUser = new SysUserBo();
String name = "用户" + UUID.randomUUID().toString().replace("-", "");
// 设置默认用户名
sysUser.setUserName(name);
// 设置默认昵称
sysUser.setNickName(name);
// 设置默认密码
sysUser.setPassword(BCrypt.hashpw("123456"));
// 设置微信openId
sysUser.setOpenId(openid);
String configValue = configService.getConfigValue("mail", "amount");
// 设置默认余额
sysUser.setUserBalance(NumberUtils.toDouble(configValue, 1));
// 注册用户,设置默认租户为0
SysUser registerUser = userService.registerUser(sysUser, "0");
// 构建登录用户信息
loginUser.setTenantId("0");
loginUser.setUserId(registerUser.getUserId());
loginUser.setUsername(registerUser.getUserName());
loginUser.setUserType(UserType.APP_USER.getUserType());
loginUser.setOpenid(openid);
loginUser.setNickName(registerUser.getNickName());
} else {
// 此处可根据登录用户的数据不同 自行创建 loginUser
loginUser.setTenantId(user.getTenantId());
loginUser.setUserId(user.getUserId());
loginUser.setUsername(user.getUserName());
loginUser.setUserType(user.getUserType());
loginUser.setNickName(user.getNickName());
loginUser.setAvatar(user.getWxAvatar());
loginUser.setOpenid(openid);
}
// 生成token
LoginHelper.loginByDevice(loginUser, DeviceType.XCX);
recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
LoginVo loginVo = new LoginVo();
// 生成令牌
loginVo.setToken(StpUtil.getTokenValue());
loginVo.setUserInfo(loginUser);
return loginVo;
}
/**
* 记录登录信息
*
* @param tenantId 租户ID
* @param username 用户名
* @param status 状态
* @param message 消息内容
*/
private void recordLogininfor(String tenantId, String username, String status, String message) {
LogininforEvent logininforEvent = new LogininforEvent();
logininforEvent.setTenantId(tenantId);
logininforEvent.setUsername(username);
logininforEvent.setStatus(status);
logininforEvent.setMessage(message);
logininforEvent.setRequest(ServletUtils.getRequest());
SpringUtils.context().publishEvent(logininforEvent);
}
}

View File

@@ -0,0 +1,10 @@
package org.ruoyi.service;
public interface WeixinUserService {
void checkSignature(String signature, String timestamp, String nonce);
String handleWeixinMsg(String body);
}

View File

@@ -0,0 +1,65 @@
package org.ruoyi.service.impl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.ruoyi.domin.ReceiveMessage;
import org.ruoyi.service.WeixinUserService;
import org.ruoyi.util.WeixinMsgUtil;
import org.ruoyi.util.WeixinQrCodeCacheUtil;
import org.springframework.stereotype.Service;
import java.util.Arrays;
@Slf4j
@Service
public class WeixinUserServiceImpl implements WeixinUserService {
private String token = "panda";
@Override
public void checkSignature(String signature, String timestamp, String nonce) {
String[] arr = new String[] {token, timestamp, nonce};
Arrays.sort(arr);
StringBuilder content = new StringBuilder();
for (String str : arr) {
content.append(str);
}
String tmpStr = DigestUtils.sha1Hex(content.toString());
if (tmpStr.equals(signature)) {
log.info("check success");
return;
}
log.error("check fail");
throw new RuntimeException("check fail");
}
@Override
public String handleWeixinMsg(String requestBody) {
ReceiveMessage receiveMessage = WeixinMsgUtil.msgToReceiveMessage(requestBody);
// 扫码登录
if (WeixinMsgUtil.isScanQrCode(receiveMessage)) {
return handleScanLogin(receiveMessage);
}
// 关注
if (WeixinMsgUtil.isEventAndSubscribe(receiveMessage)) {
return receiveMessage.getReplyTextMsg("感谢您的关注!");
}
return receiveMessage.getReplyTextMsg("收到(自动回复)");
}
/**
* 处理扫码登录
*
* @param receiveMessage
* @return
*/
private String handleScanLogin(ReceiveMessage receiveMessage) {
String qrCodeTicket = WeixinMsgUtil.getQrCodeTicket(receiveMessage);
if (WeixinQrCodeCacheUtil.get(qrCodeTicket) == null) {
String openId = receiveMessage.getFromUserName();
WeixinQrCodeCacheUtil.put(qrCodeTicket, openId);
}
return receiveMessage.getReplyTextMsg("你已成功登录!");
}
}

View File

@@ -0,0 +1,24 @@
package org.ruoyi.util;
import org.apache.commons.lang3.RandomStringUtils;
import java.util.UUID;
/**
* @author https://www.wdbyte.com
*/
public class KeyUtils {
public synchronized static String key6() {
return RandomStringUtils.randomAlphanumeric(6);
}
public synchronized static String key16() {
return RandomStringUtils.randomAlphanumeric(16);
}
public static String uuid32() {
return UUID.randomUUID().toString().replace("-", "");
}
}

View File

@@ -0,0 +1,81 @@
package org.ruoyi.util;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.common.core.service.ConfigService;
import org.ruoyi.domin.WeixinQrCode;
import org.springframework.stereotype.Component;
import java.net.URI;
import java.time.LocalDateTime;
/**
* @author https://www.wdbyte.com
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class WeixinApiUtil {
private final ConfigService configService;
private static String QR_CODE_URL_PREFIX = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=";
private static String ACCESS_TOKEN = null;
private static LocalDateTime ACCESS_TOKEN_EXPIRE_TIME = null;
/**
* 二维码 Ticket 过期时间
*/
private static int QR_CODE_TICKET_TIMEOUT = 10 * 60;
/**
* 获取 access token
*
* @return
*/
public synchronized String getAccessToken() {
if (ACCESS_TOKEN != null && ACCESS_TOKEN_EXPIRE_TIME.isAfter(LocalDateTime.now())) {
return ACCESS_TOKEN;
}
String api = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + getKey("appid") + "&secret="
+ getKey("secret");
String result = HttpUtil.get(api);
JSONObject jsonObject = JSON.parseObject(result);
ACCESS_TOKEN = jsonObject.getString("access_token");
ACCESS_TOKEN_EXPIRE_TIME = LocalDateTime.now().plusSeconds(jsonObject.getLong("expires_in") - 10);
return ACCESS_TOKEN;
}
/**
* 获取二维码 Ticket
*
* https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html
*
* @return
*/
public WeixinQrCode getQrCode() {
String api = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + getAccessToken();
String jsonBody = String.format("{\n"
+ " \"expire_seconds\": %d,\n"
+ " \"action_name\": \"QR_STR_SCENE\",\n"
+ " \"action_info\": {\n"
+ " \"scene\": {\n"
+ " \"scene_str\": \"%s\"\n"
+ " }\n"
+ " }\n"
+ "}", QR_CODE_TICKET_TIMEOUT, KeyUtils.uuid32());
String result = HttpUtil.post(api, jsonBody);
log.info("get qr code params:{}", jsonBody);
log.info("get qr code result:{}", result);
WeixinQrCode weixinQrCode = JSON.parseObject(result, WeixinQrCode.class);
weixinQrCode.setQrCodeUrl(QR_CODE_URL_PREFIX + URI.create(weixinQrCode.getTicket()).toASCIIString());
return weixinQrCode;
}
public String getKey(String key) {
return configService.getConfigValue("weixin", key);
}
}

View File

@@ -0,0 +1,66 @@
package org.ruoyi.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.ruoyi.domin.ReceiveMessage;
/**
* @author https://www.wdbyte.com
*/
public class WeixinMsgUtil {
// 事件-关注
private static String EVENT_SUBSCRIBE = "subscribe";
/**
* 微信消息转对象
*
* @param xml
* @return
*/
public static ReceiveMessage msgToReceiveMessage(String xml) {
JSONObject jsonObject = JSON.parseObject(XmlUtil.xml2json(xml));
ReceiveMessage receiveMessage = new ReceiveMessage();
receiveMessage.setToUserName(jsonObject.getString("ToUserName"));
receiveMessage.setFromUserName(jsonObject.getString("FromUserName"));
receiveMessage.setCreateTime(jsonObject.getString("CreateTime"));
receiveMessage.setMsgType(jsonObject.getString("MsgType"));
receiveMessage.setContent(jsonObject.getString("Content"));
receiveMessage.setMsgId(jsonObject.getString("MsgId"));
receiveMessage.setEvent(jsonObject.getString("Event"));
receiveMessage.setTicket(jsonObject.getString("Ticket"));
return receiveMessage;
}
/**
* 是否是订阅事件
*
* @param receiveMessage
* @return
*/
public static boolean isEventAndSubscribe(ReceiveMessage receiveMessage) {
return StringUtils.equals(receiveMessage.getEvent(), EVENT_SUBSCRIBE);
}
/**
* 是否是二维码扫描事件
*
* @param receiveMessage
* @return
*/
public static boolean isScanQrCode(ReceiveMessage receiveMessage) {
return StringUtils.isNotEmpty(receiveMessage.getTicket());
}
/**
* 获取扫描的二维码 Ticket
*
* @param receiveMessage
* @return
*/
public static String getQrCodeTicket(ReceiveMessage receiveMessage) {
return receiveMessage.getTicket();
}
}

View File

@@ -0,0 +1,34 @@
package org.ruoyi.util;
import java.util.LinkedHashMap;
/**
* 微信二维码缓存工具类
*
* @author https://www.wdbyte.com
*/
public class WeixinQrCodeCacheUtil {
private static long MAX_CACHE_SIZE = 10000;
private static LinkedHashMap<String, String> QR_CODE_TICKET_MAP = new LinkedHashMap<>();
/**
* 增加一个 Ticket
* 首次 putvalue 为 ""
* 再次 put: value 有 openId若openId已经存在则已被扫码
*
* @param key
* @param value
*/
public synchronized static void put(String key, String value) {
QR_CODE_TICKET_MAP.put(key, value);
if (QR_CODE_TICKET_MAP.size() > MAX_CACHE_SIZE) {
String first = QR_CODE_TICKET_MAP.keySet().stream().findFirst().get();
QR_CODE_TICKET_MAP.remove(first);
}
}
public synchronized static String get(String key) {
return QR_CODE_TICKET_MAP.remove(key);
}
}

View File

@@ -0,0 +1,28 @@
package org.ruoyi.util;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
/**
* @author https://www.wdbyte.com
*/
@Slf4j
public class XmlUtil {
public static String xml2json(String requestBody) {
requestBody = StringUtils.trim(requestBody);
XmlMapper xmlMapper = new XmlMapper();
JsonNode node = null;
try {
node = xmlMapper.readTree(requestBody.getBytes());
ObjectMapper jsonMapper = new ObjectMapper();
return jsonMapper.writeValueAsString(node);
} catch (Exception e) {
log.error("xml 2 json error,msg:" + e.getMessage(), e);
}
return null;
}
}