【抽取servlet共性】实现高内聚提高开发效率
平常我们写Servlet时总是一个功能一个Servlet,然后发现自己写的Servlet文件一大堆。
就比如登录,注册,退出,验证等等。
但是我们仔细分析登录,注册,退出,验证等等好像都是和用户有关的。那么我们能不能将与用户有关的写一个Servlet,与货物有关的写一个Servet呢?
再仔细想,平常我们写Java项目时总是采用三层架构模式,那么能不能有一种方法将我们写的所有Servlet也像Service层或者Dao层一样,写一个模块的Servlet,这个Servlet里包含这个模块相应的方法,通过调用这个模块的方法来实现不同功能呢?
回想一下,我们现在编写的Servlet方法,都是extends自HttpServlet,HttpServlet又extends自GenericServlet,在GenericServlet中实现了Servlet这个接口,而Servlet接口中定义了Servlet的规范,Tomcat在运行的时候,要去执行Servlet中的service方法,而在HttpServlet中重写了service方法,通过判断你是get还是post或者其他请求,然后去调用相应的方法,实现了方法的分发。
现在我们不让编写的Servlet去继承HttpServlet,而是去继承我们自己编写的一个BaseServlet,让这个BaseServlet去继承HttpServlet,既然HttpServet中重写了service方法,实现了通过不同的请求来调用不同的方法,我们就从BaseServlet中重写service方法,通过判断来实现某个模块的所请求的方法。
那么根据请求来获取Servlet所要实现的功能,我们可以在请求路径上做些准备,比如用户需要注册的时候,我可以将对应请求路径设置为/user/regist。这样我们的请求路径上就出现了我们所需要的调用的方法名了。
紧接着又出现个问题,光有方法名我们怎么才能让UserSerlvet调用对应的方法呢?
仔细一想,通过方法名实现方法我们可以通过反射实现,通过反射我们可以获取类的方法并且可以实现对应的方法。
package cn.siyi.travel.web.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.InvocationTargetException;
import java.lang.reflect.Method;
public class BaseServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求路径 例如:/user/regist
String uri = req.getRequestURI();
//获取方法名称 regist
String methodName = uri.substring(uri.lastIndexOf('/') + 1);
//获取方法对象Method
try {
//当子类调用父类的service时,this代表子类对象 例如UserServlet
Method method = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
//实现对应方法
method.invoke(this,req,resp);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
以下这段代码的共性:
根据不同的参数值调用不同的方法(约定前提:对应模块的Servlet类继承自BaseServlet,并且不能重写service方法)
用户访问的URI:
- 用户注册: /user/regist
- 用户登录:/user/login
- 用户退出:/user/exit
- 用户激活:/user/active
- 用户查询:/user/findOne
package cn.siyi.travel.web.servlet;
import cn.siyi.travel.domain.ResultInfo;
import cn.siyi.travel.domain.User;
import cn.siyi.travel.service.UserService;
import cn.siyi.travel.service.impl.UserServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.beanutils.BeanUtils;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
@WebServlet("/user/*") // /user/add /user/find
public class UserServlet extends BaseServlet {
private UserService service = new UserServiceImpl();
/**
* 注册功能
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
protected void regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String check = request.getParameter("check");
//从session中获取验证码
HttpSession session = request.getSession();
String checkcode_server = (String)session.getAttribute("CHECKCODE_SERVER");
session.removeAttribute("CHECKCODE_SERVER");
//比较
if(checkcode_server==null || !checkcode_server.equalsIgnoreCase(check)){
ResultInfo resultInfo = new ResultInfo();
resultInfo.setFlag(false);
resultInfo.setErrorMsg("验证码错误");
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(resultInfo);
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(json);
return;
}
//获取数据
Map<String, String[]> map = request.getParameterMap();
//封装对象
User user = new User();
try {
BeanUtils.populate(user,map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
boolean flag = service.regist(user);
ResultInfo resultInfo = new ResultInfo();
if(flag){
resultInfo.setFlag(true);
}else{
resultInfo.setFlag(false);
resultInfo.setErrorMsg("注册失败!");
}
//将resultInfo对象序列化为json
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(resultInfo);
//将json数据写回客户端
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(json);
}
/**
* 登录功能
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
protected void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//验证码验证
String check = request.getParameter("check");
HttpSession session = request.getSession();
String checkcode_server = (String)session.getAttribute("CHECKCODE_SERVER");
session.removeAttribute("CHECKCODE_SERVER");
ResultInfo resultInfo = new ResultInfo();
ObjectMapper objectMapper = new ObjectMapper();
response.setContentType("application/json;charset=utf-8");
if(checkcode_server==null || !checkcode_server.equalsIgnoreCase(check)){
resultInfo.setFlag(false);
resultInfo.setErrorMsg("验证码错误");
objectMapper.writeValue(response.getOutputStream(),resultInfo);
return;
}
//获取用户名和密码数据
Map<String, String[]> map = request.getParameterMap();
//封装User对象
User user = new User();
try {
BeanUtils.populate(user,map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
User u = service.login(user);
//判断
if(u == null){
//用户名或密码错误
resultInfo.setFlag(false);
resultInfo.setErrorMsg("用户名或密码错误");;
}else if(!"Y".equals(u.getStatus())){
resultInfo.setFlag(false);
resultInfo.setErrorMsg("您尚未激活,请激活");
}else{
request.getSession().setAttribute("user",u);
resultInfo.setFlag(true);
}
objectMapper.writeValue(response.getOutputStream(),resultInfo);
}
/**
* 查询单个对象
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
protected void findOne(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Object user = request.getSession().getAttribute("user");
ObjectMapper objectMapper = new ObjectMapper();
response.setContentType("application/json;charset=utf-8");
objectMapper.writeValue(response.getOutputStream(),user);
}
/**
* 退出功能
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
protected void exit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//销毁session
request.getSession().invalidate();
//跳转到登录页面
response.sendRedirect(request.getContextPath()+"/login.html");
}
/**
* 激活功能
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
protected void active(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取激活码
String code = request.getParameter("code");
if(code != null){
boolean flag = service.active(code);
String msg;
if(flag){
//激活成功
msg = "激活成功,请<a href='login.html'>登录</a>";
}else{
//激活失败
msg = "激活失败,请联系管理员";
}
response.setContentType("text/html;charset=utf-8");
response.getWriter().write(msg);
}
}
}
这样我们就不用分别去写每个功能的Servlet了,只需要写一个对应方法即可,并且我们还可以共享一些数据,比如session。
虽然重写了service方法实现了方法的分发,但是service方法底层做了一些优化,如果我们直接就用几行简单的代码去重写了service方法,它底层一些优化好的机制我们就无法体验到。
所以,现在我们有另一种方案,我们还是让BaseServlet去继承HttpServlet,并分别去继承doGet与doPost方法,我们在doGet或者doPost里再去实现方法的分发,这样我们既抽取了servlet,也能体验到service方法底层的优化机制。
但是这样的话感觉代码量又增加了一点,看情况选择吧。