JavaWeb 多個Servlet整合優化 由於一個Servlet只能接收一個地址的http請求,如果系統複雜度提高,就會有很多Servlet類。例如,對銷售系統來說,可能會有OederInsertServlet, OrderUpdateServlet, OrderDeleteSerlvet, Or ...
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
頁面響應
調用成功