在实际的开发中,我们经常会遇见一个业务逻辑下会有多个功能的情况,对应到java中也就是会产生多个Servlet.
例如用户业务下就有登陆,注册,退出功能(如图1):
当Servlet过多对性能会产生影响,那么我们能不能把同一逻辑下的多个Servlet合为一个Servlet呢?
对于这个问题的核心是一个Servlet如何判断出浏览器客户端的真实请求功能呢?这里我们可以通过请求传递参数来实现,服务器获取到请求的参数,通过判断参数来调用不同的方法来实现业务功能.
注意:这里客户端必须与服务器端进行约定,我这里使用的是method代表功能.
思想:如下图所示:
环境搭建:
浏览器客户端代码我使用的是JSP文件
客户端JSP代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%--
向服务器发送请求
约定好键值对数据,告知服务器
请求的功能是什么
--%>
登陆
注册
退出
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" %>
Title
添加订单
移除订单
查看订单
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("查看订单");
}
}
效果如下依然可以实现,并且更加简洁: