一、问题描述
在做 SSO 单点登录时( 认证中为CAS服务对接 )。在完成对用户ticket票根校验后,返回了用户信息有关 XML 数据片段,例如下:
<cas:serviceResponse xmlns:cas="http://www.xxx.xx/xx/cas">
<cas:authenticationSuccess>
<cas:user>200161</cas:user>
<cas:username>张三</cas:username>
<cas:usertype>TEACHER</cas:usertype>
</cas:authenticationSuccess>
</cas:serviceResponse>
获取到CAS 认证中心返回的数据后,通过 Java中的 Pattern 和 Matcher 对象来获取XML 中的数据!
Pattern 和 Matcher 是用于处理正则表达式的两个主要类。
它们的主要作用和用途如下:
- Pattern 类
- 作用:Pattern类是用于编译正则表达式的类。它代表一个编译后的正则表达式,可以对输入的字符串执行匹配操作。
- 创建:通过调用静态方法 Pattern.compile() 来创建 Pattern 对象,并传入需要的正则表达式作为参数。
- Matcher 类
- 作用:Matcher 类是对输入字符串进行匹配和搜索的类。它与 Pattern 对象一起使用,用于执行匹配操作。
- 创建:通过调用 Pattern 对象的 matcher 方法创建 Matcher 对象,并传入需要匹配的字符串。
// 解析XML数据,获取指定信息
Pattern pt = Pattern.compile("<cas:user>(.*)</cas:user>");
Matcher matcher = pt.matcher(resultXml);
while (matcher.find()){
group0 = matcher.group(0).trim();
group1 = matcher.group(1).trim();
}
上面通过 Pattern 和 **Matcher **来解析出用户信息,但是使用到了 matcher.group(0) 获取的用户信息! 导致后续操作(我的后续操作是拿到的用户信息进行特定的加密后封装一个重定向路径)中使用获取到的用户信息一直失败,也没找到原因!!
- 后面找到问题所在:使用 group(n) 方法获取匹配的内容:group(0) 返回整个匹配的部分,group(1) 返回第一个括号内的内容 !
这里至于为什么没有发现 通过 matcher.group(0) 和 matcher.group(1) 获取到的值不一样! 是因为我将这两值都直接返回到视图中渲染了,但在视图中展示的内容 他们是一样的!!
二、复现坑
controller 层代码:
package com.example.gsxy_sso_u8cloud.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @ClassName : XmlBugController
* @Description : 测试解析XML文件时出现的坑!
* @Author : AD
*/
@RestController
@RequestMapping("/xmlbug")
public class XmlBugController {
/**
* Description: 模拟解析XML文件的接口
* 通过 group(0) / group(1) 对比从XML数据中提取的值!
*
* @param
* @return java.lang.String
* @date 2024-10-24
*/
@GetMapping("/getXmlInfo")
public String getXmlInfo(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 模拟Cas认证校验成功后,返回的用户信息数据 resultXml
String resultXml = "<cas:serviceResponse xmlns:cas=\"http://www.xxx.xxx/xx/cas\"> "+
" <cas:authenticationSuccess> "+
" <cas:user>200161</cas:user> "+
" <cas:username>张三</cas:username> "+
" <cas:usertype>TEACHER</cas:usertype> "+
" </cas:authenticationSuccess> "+
" </cas:serviceResponse> ";
/**
* 定于两个接收解析数据的对象 分别接收 group(0) 和 group(1)
* */
String group0 = "";
String group1 = "";
// 解析XML数据,获取指定信息
Pattern pt = Pattern.compile("<cas:user>(.*)</cas:user>");
Matcher matcher = pt.matcher(resultXml);
while (matcher.find()){
group0 = matcher.group(0).trim();
group1 = matcher.group(1).trim();
}
System.out.println("从XML中解析出来的 group0 = " + group0);
System.out.println("从XML中解析出来的 group1 = " + group1);
/*
// 设置响应内容类型为 XML
response.setContentType("application/xml;charset=UTF-8");
// 创建 XML 内容
String xmlContent = "<cas:user>200161</cas:user>";
// 输出 XML 内容
response.getWriter().write(xmlContent);
*/
return "group0 = "+ group0+" \t\n"+
"group1 = "+ group1+" \t\n";
}
}
访问controller 接口查看响应数据:
可以看出在浏览器中渲染出来的数据,显式的结果是一样的!!!~~ 所以这里就导致我没发现端倪( 因为远程服务器的配置特殊 )!!!
但是我们可以通过 页面元素 和 网络响应中看出他们的不同之处!
- 页面元素:
- 网络响应:
为什么是使用 group(1) 而不是 group(0) 呢?
在使用正则表达式时,group(0) 和 group(1) 的含义是不同的:
- group(0):
○ 返回整个匹配的字符串。这是正则表达式匹配结果的完整文本,包括所有的匹配内容。
○ 在你的例子中,group(0) 将返回整个匹配的内容,例如:“cas:user200161</cas:user>”。
- group(1):
○ 返回第一个捕获组中的内容。当你在正则表达式中使用括号 () 来创建捕获组时,你可以通过 group(1) 访问第一个捕获组所匹配的内容。
○ 在你的例子中,group(1) 将返回被 cas:user 标签包围的内容,即实际的用户 ID,例如 “200161”。