您的位置:首页 > 编程语言

结合代码分析--BaseServlet存在的意义(刚接触servlet的必看)

2018-01-09 09:37 323 查看

看到一个jsp/servlet实现MVC模式的项目中使用了BaseServlet,一开始并不理解这个类的作用,感觉是多此一举,但看了几篇文章后才发现原来是自己写的代码太low了,学识尚浅理解不了。但大牛总是从菜鸟走过来的嘛,虚心学习总没错。 故将自己的理解分享在博客上。

介绍

BaseServlet并不是什么很高大上的东西,它只是一个普通的、继承了HttpServlet类并重写了其中service方法的类。

使用方式

继承该类

存在的意义

对于刚刚接触编程的人来说,如果刚学完servlet,写一个增删改查的demo一般都会分别写四个servlet类,分别对应四种操作,就像这样:
AddServlet
 
DeleteServlet
 
UpdateServlet
 
QueryServlet
,但这样不仅代码冗余的非常厉害,而且还需要对每个servlet一一配置,(特别是servlet3.0以前需要在web.xml中配置,会非常麻烦,web.xml文件也会变得很大,若修改配置很难找到对应)。相应的整个项目也会显得很大,为了解决这种问题就有了改进的版本。

--------------------------------------- 分割线 ---------------------------------------------------

一些已经接触编程一段时间的人会将增删改查四个操作写在一个servlet中,调用某个方法的时候只需要在servlet映射的url后面添加参数,比如:
<a
href="/testServlet?method=add">添加</a>
,然后在servlet中添加if判断method参数的值来调用不同的方法,类似这样:

String method = request.getParameter("method");
if(method.equals("add")) {
add(...);   //省略参数 下同
} else if(method.equals("update")) {
delete();
} else if(method.equals("query")) {
update(...);
} else{
query(...);
}

这确实是个不错的办法(因为我在学习BaseServlet之前用的就是这种方式 哈哈哈),但我现在可以理解为:编写这段代码的人很有想法,但编程水平还仅仅在初级阶段。因为他只考虑到完成了增删改查的功能,并没有考虑到对功能的扩展。如果增加一个功能(假设一个功能对应一个方法),他要修改一次if语句的判断,那如果增加一百个功能呢?难道要改一百次代码?更何况有时候项目已经上线,难道要用户自己修改? 这还仅仅是一个servlet,对应一个domain类的操作,稍微大一点的项目至少就有一二十个domain类吧(我也没接触过,猜的,但绝对不会少),每个servlet都有着那么多操作,那要写多少if语句判断啊。

--------------------------------------- 分割线 ---------------------------------------------------

所以BaseServlet就应运而生了,它作为一个项目中所有servlet的基类,(个人感觉该类属于设计模式中的前端控制器,类似SpringMVC的DispatcherServlet),其中并没有任何的业务逻辑,只负责将请求处理后分发到不同的servlet进行不同的处理。

下面就结合代码理解一下该类(因为BaseServlet类只重写了service方法所以我只贴出service方法的代码,而且代码可能与你网上找到的有些细节方面不太相同,但基本原理是一样的),我会将解释写在代码的注释里:

public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//下面这个if语句可以不用看,这里用到了我项目中另一个类:GetRequest,该类继
4000
承了HttpRequestWrapper,将request进行了包装,主要是防止乱码
if(((HttpServletRequest)request).getMethod().equalsIgnoreCase("get")) {
if(!(request instanceof GetRequest)) {
request = new GetRequest((HttpServletRequest)request);
}
} else {
((HttpServletRequest)request).setCharacterEncoding("utf-8");
}

//设置response的返回数据格式以及字符编码
response.setContentType("text/html;charset=UTF-8");
//在这里获取前台传来的method参数
String methodName = ((HttpServletRequest)request).getParameter("method");
/*
* Method类,是java反射机制使用到的一个类
* API对该类的解释是:提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。
* 看到这里是不是有点清楚BaseServlet是怎么调用方法的了?
* 这里先定义了一个Method的引用,遵循编写代码的规范原则,在try-catch外定义引用,块内实现
*/
Method method = null;

try {
/* 这行代码的意思是实例化一个以methodName命名,以HttpServletRequest对象和HttpServletResponse对象做参数的方法
* 大家都知道this指的是调用当前方法的类的对象
* 所以不要想当然的认为this指的是BaseServlet对象,而是继承自BaseServlet的、与你请求的url相匹配的Servlet
* 这个Servlet当然由你自己实现
*/
method = this.getClass().getMethod(methodName, new Class[]{HttpServletRequest.class, HttpServletResponse.class});
} catch (Exception var10) {
//你自定义的servlet中没有对应的方法时,处理异常。
throw new RuntimeException("您要调用的方法:" + methodName + "它不存在!", var10);
}

try {
//这行代码表示调用了刚才实例化的Method对象所对应的方法,并用e接收方法的返回值
String e = (String)method.invoke(this, new Object[]{request, response});
//对e进行一些必要的判断
if(e != null && !e.trim().isEmpty()) {
/* 这里需要解释一下返回字符串的构成
* 可以直接返回要跳转的视图名,这样将会跳转到对应视图
* 若返回视图名的字符串前指定了转发的方式,如:f:list.jsp 或 r:list.jsp
* 那么下面语句会判断使用何种方式转发视图
*/
int index = e.indexOf(":");
if(index == -1) {
//没有指定视图的转发方式 ((HttpServletRequest)request).getRequestDispatcher(e).forward((ServletRequest)request, response);
} else {
String start = e.substring(0, index);
String path = e.substring(index + 1);
if(start.equals("f")) {
//如果指定了f,则使用forward方式跳转 ((HttpServletRequest)request).getRequestDispatcher(path).forward((ServletRequest)request, response);
} else if(start.equals("r")) {
//如果指定了r,则使用redirect方式重定向 response.sendRedirect(((HttpServletRequest)request).getContextPath() + path);
}
}
}

} catch (Exception var9) {
throw new RuntimeException(var9);
}
}

代码的执行流程如上。总结一下:

该方法中使用了反射机制来调用方法,不论你的Servlet中有多少方法,这段代码都不需要改变,只需要你提供方法名和参数列表就可以完成调用。若有别的domain类添加,只需要将对应的Servlet继承该类即可,不需要额外的代码。 继承后你只需要关心自己的逻辑即可,不用关心怎样被调用。

以上就是我对BaseServlet的理解,如有不同见解希望能一起讨论,如果写的有错欢迎指正

参考资料:

http://blog.csdn.net/sinat_34423196/article/details/52585648

http://www.runoob.com/design-pattern/front-controller-pattern.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  servlet 设计模式