在實際的開發中,我們經常會遇見一個業務邏輯下會有多個功能的情況,對應到java中也就是會產生多個Servlet.
例如用戶業務下就有登陸,注冊,退出功能(如圖1):
當Servlet過多對性能會產生影響,那么我們能不能把同一邏輯下的多個Servlet合為一個Servlet呢?
對于這個問題的核心是一個Servlet如何判斷出瀏覽器客戶端的真實請求功能呢?這里我們可以通過請求傳遞參數來實現,服務器獲取到請求的參數,通過判斷參數來調用不同的方法來實現業務功能.
注意:這里客戶端必須與服務器端進行約定,我這里使用的是method代表功能.
思想:如下圖所示:
環境搭建:
瀏覽器客戶端代碼我使用的是JSP文件
客戶端JSP代碼:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<%--
向服務器發送請求
約定好鍵值對數據,告知服務器
請求的功能是什么
--%>
<body>
<a href="${pageContext.request.contextPath}/user?method=login">登陸</a><br>
<a href="${pageContext.request.contextPath}/user?method=reg">注冊</a><br>
<a href="${pageContext.request.contextPath}/user?method=exit">退出</a>
</body>
</html>
Java代碼:
package com.xfz.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(urlPatterns = "/user")
public class UserServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* 獲取提交的參數
* 并判斷內容調用方法
* */
String method = request.getParameter("method");
if("login".equals(method)){
login(request,response);
}else if("reg".equals(method)){
reg(request,response);
}else if("exit".equals(method)){
exit(request,response);
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
public void login(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
System.out.println("處理登陸");
}
public void reg(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
System.out.println("處理注冊");
}
public void exit(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
System.out.println("處理退出");
}
}
運行效果:
到這里我們的需求基本實現了,但是此處的servlet代碼還有優化的空間,比如當用戶的功能太多了,我們判斷方法的邏輯也會變得很多,會出現很多if,else if的情況.所以這里我們將使用反射的來優化過多的邏輯判斷問題.UserServlet進行如下優化:
package com.xfz.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
@WebServlet(urlPatterns = "/user")
public class UserServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* 獲取提交的參數
* 并判斷內容調用方法
* */
String method = request.getParameter("method");
//非空判斷
if(method == null || "".equals(method)){return;}
//反射獲取該類class對象
Class clazz = this.getClass();
//method就是方法名,反射獲取方法
try {
Method md = clazz.getMethod(method, HttpServletRequest.class, HttpServletResponse.class);
md.invoke(this,request,response);
} catch (Exception e) {
e.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
public void login(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
System.out.println("處理登陸");
}
public void reg(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
System.out.println("處理注冊");
}
public void exit(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
System.out.println("處理退出");
}
}
效果如下,相關處理依然能夠實現,并且無需過多的邏輯判斷:
做到這里,我們發現在同一個業務下基本沒有問題了,但是多個業務下就會出現代碼重復的問題.
這里的用戶模塊,訂單模塊,商品模塊都會使用同一的步驟:獲取客戶端參數/反射技術獲取方法/調用方法,因為他們是不同的業務模塊,所以不能使用一個Servlet,那么對于這種情況下的相同代碼我們可以使用繼承的方式,進行向上抽取來優化過多重復代碼的問題.如下:
優化如下:
第一步:創建BaseServlet類繼承HttpServlet 重寫doGet() doPost()方法
第二步:將重復代碼向上提取到該類doGet()方法中
第三步:因為該類不需要被訪問也不需要創建對象,所以無需注解,類也使用abstract修飾
package com.xfz.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
abstract class BaseServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* 獲取提交的參數
* 并判斷內容調用方法
* */
String method = request.getParameter("method");
//非空判斷
if(method == null || "".equals(method)){return;}
//反射獲取該類class對象
Class clazz = this.getClass();
//method就是方法名,反射獲取方法
try {
Method md = clazz.getMethod(method, HttpServletRequest.class, HttpServletResponse.class);
md.invoke(this,request,response);
} catch (Exception e) {
e.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
UserServlet代碼:
第一步:繼承BaseServlet類
第二步:由于父類中有doGet()和doPost()方法,所以該類不需要,刪除
package com.xfz.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(urlPatterns = "/user")
public class UserServlet extends BaseServlet {
public void login(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
System.out.println("處理登陸");
}
public void reg(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
System.out.println("處理注冊");
}
public void exit(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
System.out.println("處理退出");
}
}
效果如圖:
到這里對于多個Servlet的抽取優化基本完成,當有別的業務如Order訂單邏輯需要我們處理時,也只需新建普通類添加注解并繼承BaseServlet,寫入相關功能方法即可.
示例:
客戶端JSP代碼:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/order?method=add">添加訂單</a><br>
<a href="${pageContext.request.contextPath}/order?method=remove">移除訂單</a><br>
<a href="${pageContext.request.contextPath}/order?method=show">查看訂單</a>
</body>
</html>
OrderServlet代碼:
package com.xfz.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(urlPatterns = "/order")
public class OrderServlet extends BaseServlet{
public void add(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
System.out.println("添加訂單");
}
public void remove(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
System.out.println("移除訂單");
}
public void show(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
System.out.println("查看訂單");
}
}
效果如下依然可以實現,并且更加簡潔: