JavaWeb 多个Servlet整合优化
由于一个Servlet只能接收一个地址的http请求,如果系统复杂度提高,就会有很多Servlet类。例如,对销售系统来说,可能会有OederInsertServlet, OrderUpdateServlet, OrderDeleteSerlvet, OrderQueryServlet等多个OrderServlet来处理订单这一种业务。看着就会很杂。如下图。同时如果请求前或请求后有一些处理的话,对应的方法就需要写很多次,维护难度也会提升
优化-同一个模块多个操作
可以只用一个Servlet接收Order这一种业务所有的接口,通过在接口添加类似operate的标志参数对不同的操作进行区分。
代码示例
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String operate = req.getParameter("operate");
if (null == operate){
doRequireOperate(req, resp);
}
SUtils.logInfo("调用前操作");
System.out.println("获取到的操作名为:" + operate);
switch (operate){
case "insert":{
System.out.println("do insert");
doInsertOperate(req, resp);
break;
}
case "update":{
System.out.println("do update");
doUpdateOperate(req, resp);
break;
}
case "delete":{
System.out.println("do delete");
doDeleteOperate(req, resp);
break;
}
case "query":{
System.out.println("do query");
doQueryOperate(req, resp);
break;
}
default:{
System.out.println("error");
}
SUtils.logInfo("调用后操作");
}
}
测试
本地访问 http://localhost:8080/mvc/ver1?operate=insert
服务器日志输出如下
优化-使用反射
目前,对业务的操作是通过switch-case进行匹配处理的,如果操作数量增多则需要多增加case语句,代码就会显得臃肿。可以考虑通过反射调用具体的执行方法
示例代码
下面展示的是核心代码
String operate = req.getParameter("operate");
System.out.println("获取到的操作名为:" + operate);
// 通过反射获取对应的方法
// 假定方法名均为do+${operate}+operate,驼峰,如operate为insert时,要调用的方法就是doInsertOperate
// Method[] methods = this.getClass().getMethods();
char[] chars = operate.toCharArray();
chars[0] -= 32;
String methodName = "do" + String.valueOf(chars) + "Operate";
// Optional<Method> targetMethod = Arrays.stream(methods).filter(m -> m.getName().equals(methodName)).findFirst();
try {
Method taragetMethod = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
taragetMethod.setAccessible(true);
taragetMethod.invoke(this, req, resp);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
优化-多个业务模块引入配置文件
当业务增多时,需要在每个业务里面单独写反射调用方法较为复杂,可以也通过反射来调用业务模块,再执行对应的方法,同时可以引入xml配置文件,来匹配对应的业务模块
代码示例
@WebServlet("/mvc/ver3/*")
public class Ver3Servlet extends HttpServlet {
private Map<String, Object> beanControllerMap = new HashMap<>();
// 初始化,读取xml文件配置controller
@Override
public void init() throws ServletException {
// super.init();
System.out.println("aaa");
try (InputStream beanConfigs = this.getClass().getClassLoader().getResourceAsStream("MvcVer3Config.xml")) {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document beanDocument = documentBuilder.parse(beanConfigs);
Element documentElement = beanDocument.getDocumentElement();
NodeList nodeList = beanDocument.getDocumentElement().getElementsByTagName("bean");
for (int i = 0; i < nodeList.getLength(); i++) {
if (Node.ELEMENT_NODE == nodeList.item(i).getNodeType()){
Element item = (Element) nodeList.item(i);
String beanName = item.getAttribute("id");
String className = item.getAttribute("class");
Class<?> beanClass = Class.forName(className);
Object bean = beanClass.getDeclaredConstructors()[0].newInstance();
beanControllerMap.put(beanName, bean);
}
}
// documentElement.get
} catch (IOException | ParserConfigurationException | SAXException | ClassNotFoundException |
InvocationTargetException | InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
System.out.println("aaa");
}
// 读取路径值,获取对应的controller对象,反射调用对应方法
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String servletPath = req.getPathInfo();
System.out.println(servletPath);
String controllerName = servletPath.split("/")[1];
String operateName = servletPath.split("/")[2];
operateName = "do" + getFirstUpper(operateName) + "Operate";
Object targetController = beanControllerMap.get(getFirstUpper(controllerName));
Method targetMethod;
try {
targetMethod = targetController.getClass().getDeclaredMethod(operateName, HttpServletRequest.class, HttpServletResponse.class);
} catch (NoSuchMethodException e) {
ErrorResponse(req, resp, e.getMessage());
e.printStackTrace();
return;
}
try {
targetMethod.invoke(targetController, req, resp);
} catch (IllegalAccessException | InvocationTargetException e) {
ErrorResponse(req, resp, e.getMessage());
e.printStackTrace();
return;
}
System.out.println("调用结束");
}
private void ErrorResponse(HttpServletRequest req, HttpServletResponse resp, String errorString) throws IOException {
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
out.println("<HTML lang=\"ch\">");
out.println(" <HEAD><TITLE>delete Servlet</TITLE></HEAD>");
out.println(" <BODY>");
out.print("所访问的模块不存在<br>");
out.print(errorString);
out.println(" </BODY>");
out.println("</HTML>");
out.flush();
out.close();
System.out.println("所访问的模块不存在");
}
private String getFirstUpper(String s){
char[] chars = s.toCharArray();
chars[0] -= 32;
return String.valueOf(chars);
}
}
解决多个业务配置问题,通过读取配置文件初始化Servlet,在收到请求时,取到对应的Servlet进行处理
配置文件示例
<?xml version="1.0" encoding="utf-8" ?>
<beans>
<bean id="A" class="com.javawebdemo.mvc.controller.AController"/>
<bean id="B" class="com.javawebdemo.mvc.controller.BController"/>
<bean id="C" class="com.javawebdemo.mvc.controller.CController"/>
<bean id="D" class="com.javawebdemo.mvc.controller.DController"/>
</beans>
测试
启动项目,访问对应路径
http://localhost:8080/mvc/ver3/a/query
页面响应
调用成功
声明:本站所发布的一切破解补丁、注册机和注册信息及软件的解密分析文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。