Servlet优化
# Servlet优化
# 反射
先前对应一个功能会请求一个servlet再找DAO,代码冗余。优化的做法是可以用一个统一的servlet处理,不同功能由这个servlet中的不同方法处理响应,在会话中存放一个操作字段,来通过swtich跳转对应方法。
上述方法switch过长时,可以使用反射技术获取方法名直接invoke调用。
Method[] methods = this.getClass().getDeclaredMethods();
for (Method m : methods) {
String methodname = m.getName();
if (methodname.equals(operate)) {
try {
m.invoke(this, req, resp);
}
catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
return;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Dispatcher控制器
通过servletpath(add.do)=>截取到add=>把add对应上它的controller。好处在于当有多个实体的servlet时,不需要一个个单独写反射代码,全部由工厂生成。
- 设置配置文件
- t通过类加载器反射,解析加载配置文件
- 获取一个个bean,并实例化对应controller对象,和key丢到map中
- 通过servletpath获取key,然后从map中找到对应的对象。
protected void init(){
//通过类加载去读取资源文件
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
//创建工厂
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
//创建DocumentBuilder对象
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
//创建document对象
Document document=documentBuilder.parse(inputStream);
//获取所有bean节点
NodeList beanNodeList = document.getElementsByTagName("bean");
for (int i = 0; i < beanNodeList.getLength(); i++) {
Node beanNode = beanNodeList.item(i);
if (beanNode.getNodeType() == Node.ELEMENT_NODE) {
Element beanElement = (Element) beanNode;
String beanId = beanElement.getAttribute("id");
String className = beanElement.getAttribute("class");
//通过类名反射创建一个实例对象
Object beanObj = forName(className).newInstance();
//beanMap<controllerName,controllerObject>
beanMap.put(beanId, beanObj);
}
}
----------
protected void service(HttpServletRequest req, HttpServletResponse resp){
//通过ServletPath()可以获取页面请求url的路径
String servletpath = req.getServletPath();
String controllerName = servletpath.substring(1,servletpath.lastIndexOf(".do"));
Object controllerBeanobj = beanMap.get(servletPath);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
这里bean节点的集合NodeList分类两类节点,一类是文本节点,一类是元素节点。NodeList类似于数组,通过NodeList.item(i)遍历,NodeList.getLength()获取长度。然后把每个节点强转成Element类型,就可以通过getAttributr()来读取每一个bean标签里的属性值。
# 提取视图资源处理
把所有的重定向和使用Thymeleaf视图都交给Dispatcher进行处理,具体做法是:
- 设置controller中所有的方法都会返回一个String,把对应要重定向的资源或者是视图资源以String的方式以为返回值输出。
- 在DispatcherController中对于重定向处理,则使用中央控制器的HttpServletResponse来进行,对于视图资源请求则直接调用父类方法即可。
Object returnObj = method.invoke(controllerBeanobj, req);
String methodReturnStr = (String) returnObj;
//视图处理
if (methodReturnStr.startsWith("redirect:")) {
String redirectStr=methodReturnStr.substring("redirect:".length());
resp.sendRedirect(redirectStr);
}
else {
super.processTemplate(methodReturnStr, req, resp);
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 统一获取请求过程传的参数
把所有业务方法中通过req.getParameter获取页面参数数据的部分都抽取出去,由Dispatcher控制器统一负责实现,要解决的问题:
- 要知道每个DeclaredMethod方法的参数名,参数类型。在idea中java-compiler添加-parameters,编译时能够通过method.getParameters()获取到的参数包含名称信息。
- 参数名称:parameter.getName()。参数类型:parameter.getType().getName()
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
if (parameter.getName().equals("req")) {
parametersValues[i] = req;
}else if(parameter.getName().equals("resp")){
parametersValues[i] = resp;
}else if(parameter.getName().equals("session")){
parametersValues[i] = req.getSession();
}else {
Object paraValue;
//针对类型名来初始化对应实参的类型
if (parameter.getType().getName().equals("java.lang.Integer")) {
paraValue= Integer.parseInt(req.getParameter(parameter.getName()));
}
parametersValues[i] = req.getParameter(parameter.getName());
}}
//将参数数组传入方法中
Object returnObj = method.invoke(controllerBeanobj, parametersValues);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
编辑 (opens new window)
上次更新: 2023/12/15, 15:49:57