写一个项目往往需要N多个Servlet,而且一个servlet只有一个doGet或doPoset.如果项目比较大,Servlet的数量会比较惊人。为了避免Servlet数量过多,我们可以在一个Servlet中写多个接收请求的方法。
具体思路:Servlet中处理请求的方法是service()方法,这说明我们需要让service()方法去调用其他方法。例如调用add()、mod()、del()、all()等方法。可以在请求时,添加一个参数,表示需要调用的方法名,然后在Servlet中判断。
实例代码:AServlet.java
public class AServlet extends javax.servlet.http.HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取method参数值
String methodName=request.getParameter("method");
//method参数值不能为空或null
if(methodName==null||methodName.trim().equals("")){
throw new RuntimeException("请输入需要访问的方法名");
}
//判断调用
if(methodName.equals("addUser")){
addUser(request,response);
}else if(methodName.equals("updateUser")){
updateUser(request,response);
}else if(methodName.equals("queryUser")){
queryUser(request,response);
}else if(methodName.equals("deleteUser")){
deleteUser(request,response);
}
}
protected void addUser(HttpServletRequest request, HttpServletResponse response)
throws javax.servlet.ServletException, IOException {
System.out.println("addUser");
}
protected void updateUser(HttpServletRequest request, HttpServletResponse response)
throws javax.servlet.ServletException, IOException {
System.out.println("updateUser");
}
protected void queryUser(HttpServletRequest request, HttpServletResponse response)
throws javax.servlet.ServletException, IOException {
System.out.println("queryUser");
}
protected void deleteUser(HttpServletRequest request, HttpServletResponse response)
throws javax.servlet.ServletException, IOException {
System.out.println("deleteUser");
}
}
这里需要注意:因为Servlet使通过service来调用其他方法,请求处理方法的签名必须与service相同:即返回值和参数,以及声明的异常都相同!
上面通过判断来决定调用那个方法,不方便扩展。这里我们通过反射,来自动调用对应的方法。
代码实现AServlet.java
public class AServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取method参数值
String methodName=request.getParameter("method");
//method参数值不能为空或null
if(methodName==null||methodName.trim().equals("")){
throw new RuntimeException("请输入需要访问的方法名");
}
//获得当前的类对象
Class clazz=this.getClass();
//创建反射中的方法对象
Method method=null;
try {
/**
* 调用类的getMethod获得方法
* 第一个参数:类名
* 后面的参数:方法的参数类型
*/
method= clazz.getDeclaredMethod(methodName,HttpServletRequest.class,HttpServletResponse.class);
} catch (NoSuchMethodException e) {
throw new RuntimeException(methodName+"(HttpServletRequest,HttpServletResponse)方法不存在!");
}
try {
/**
* 对比正常调用方法:this.addUser(request,response)
*/
method.invoke(this,request,response);
} catch (Exception e) {
System.out.println(methodName+"(HttpServletRequest,HttpServletResponse)方法内部出现了异常!");
throw new RuntimeException(e);
}
}
protected void addUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("addUser");
}
protected void updateUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("updateUser");
}
protected void queryUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("queryUser");
}
protected void deleteUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("deleteUser");
}
}
这里的Method getDeclaredMethod()和Method getMethod()需要区分一下:
- getMethod():访问本类中定义的公共方法
- getDeclaredMethod():访问本类中定义的所有方法
再进一步考虑,如果有多个Servlet,反射代码可以只写一次吗?
解决方案就是,将反射写在一个所有Servlet都继承的父类里面,下面我们就写一个这样的父类:BaseServlet.java
public class BaseServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取method参数值
String methodName=request.getParameter("method");
//method参数值不能为空或null
if(methodName==null||methodName.trim().equals("")){
throw new RuntimeException("请输入需要访问的方法名");
}
//获得当前的类对象
Class clazz=this.getClass();
//创建反射中的方法对象
Method method=null;
try {
/**
* 调用类的getMethod获得方法
* 第一个参数:类名
* 后面的参数:方法的参数类型
*/
method= clazz.getDeclaredMethod(methodName,HttpServletRequest.class,HttpServletResponse.class);
} catch (NoSuchMethodException e) {
throw new RuntimeException(methodName+"(HttpServletRequest,HttpServletResponse)方法不存在!");
}
try {
/**
* 对比正常调用方法:this.addUser(request,response)
*/
method.invoke(this,request,response);
} catch (Exception e) {
System.out.println(methodName+"(HttpServletRequest,HttpServletResponse)方法内部出现了异常!");
throw new RuntimeException(e);
}
}
}
AServlet.java
public class AServlet extends BaseServlet {
protected void addUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("addUser");
}
protected void updateUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("updateUser");
}
protected void queryUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("queryUser");
}
protected void deleteUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("deleteUser");
}
}
BServlet.java
public class BServlet extends BaseServlet {
protected void addNews(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("addNews");
}
protected void editNews(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("editNews");
}
}
这里补充一个包含转发重定向的处理技巧:
很多时候我们访问函数需要实现转发重定项等作用,如果每次都在函数中写,可能有很多重复的代码。现在我们有了BaseServlet,可以把转发重定项等代码在BaseServlet中写,这样只要写一遍。
重写BServlet
public class BServlet extends BaseServlet {
protected String addNews(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("addNews");
//返回转发
return "f:/index.jsp";
}
protected String editNews(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("editNews");
//返回重定项
return "r:"+request.getContextPath()+"/index.jsp";
}
}
在需要转发重定项的函数直接在函数结束时返回一个字符串,包含一个标志字母(如f或r等),以及地址。
重写BaseServlet
public class BaseServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取method参数值
String methodName=request.getParameter("method");
//method参数值不能为空或null
if(methodName==null||methodName.trim().equals("")){
throw new RuntimeException("请输入需要访问的方法名");
}
//获得当前的类对象
Class clazz=this.getClass();
//创建反射中的方法对象
Method method=null;
try {
/**
* 调用类的getMethod获得方法
* 第一个参数:类名
* 后面的参数:方法的参数类型
*/
method= clazz.getDeclaredMethod(methodName,HttpServletRequest.class,HttpServletResponse.class);
} catch (NoSuchMethodException e) {
throw new RuntimeException(methodName+"(HttpServletRequest,HttpServletResponse)方法不存在!");
}
try {
/**
* 对比正常调用方法:this.addUser(request,response)
*
* 返回值为一个字符串
* 包好:表示为转发或是重定项
* r:代表重定项
* f:代表转发
*/
String retstr = (String) method.invoke(this,request,response);
//返回的字符串不能为空或是null
if(retstr==null||retstr.equals("")){
return;
}
if (retstr.contains(":")) {
int index=retstr.indexOf(":");
if(retstr.charAt(0)=='f'){//转发
request.getRequestDispatcher(retstr.substring(index+1)).forward(request,response);
}else if(retstr.charAt(0)=='r'){//重定向
response.sendRedirect(retstr.substring(index+1));
}
}
} catch (Exception e) {
System.out.println(methodName+"(HttpServletRequest,HttpServletResponse)方法内部出现了异常!");
throw new RuntimeException(e);
}
}
}