一个请求对应一个servlet,但是这样存在的问题是servlet会越来越多。
二、优化1(合并成一个servlet)将一系列的请求都对应一个servlet,通过一个operate的值来决定调用servlet中的哪个方法,使用switch,但是随着项目的业务规模扩大,会有很多servlet,这样就会充斥着大量的switch,效率低下。
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
String operate = request.getParameter("operate");
if(StringUtil.isEmpty(operate)){
operate = "index";
}
switch (operate){
case "index":index(request,response);break;
case "edit":edit(request,response);break;
case "add":add(request,response);break;
case "del":del(request,response);break;
case "update":update(request,response);break;
default:throw new RuntimeException("operate非法");
}
}
三、优化2(反射)
在servlet中使用反射技术,规定operate的值和方法名一致,那么接收到operate的值是什么就表明我们需要调用对应的方法相应,如果找不到对应方法则抛出异常,但是还是存在一定问题:每个servlet都存在类似的反射方法。
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
String operate = request.getParameter("operate");
if(StringUtil.isEmpty(operate)){
operate = "index";
}
//获取当前类所有方法
Method[] methods = this.getClass().getDeclaredMethods();
for (Method m :methods){
//获取方法名称
String methodName = m.getName();
if(operate.equals(methodName)){
//找到方法,通过反射调用
try {
m.invoke(this,request,response);
return;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
throw new RuntimeException("operate非法");
}
四、优化3(dispatcherServlet)
设计中央控制器:dispatcherServlet。
多个servlet改为controller(去掉注解),由dispatcher统一控制;
所以需要先根据请求的网址/xxx找到对应的controller,再调用其中的方法。
1、根据url定位到能够处理这个请求的controller组件
新建DispatcherServlet类
1)从url中提取servletPath:/fruit.do -> fruit;
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
//例url:http://localhost:8080/1/hello.do
//那么servletPath是:/hello.do
String servletPath = request.getServletPath();
//1、使用截取,获得hello
servletPath = servletPath.substring(1);
int lastDotIndex = servletPath.lastIndexOf(".do");
servletPath = servletPath.substring(0,lastDotIndex);
2)根据fruit找到对应的组件:FruitController,这个对应的依据存储在applicationContext.xml中,通过DOM技术解析XML文件,在中央控制器中形成一个beanMap容器,用来存放所有Controller组件;
以下方法解析xml文件,根据bean节点找到id和class,使用Map集合保存。
private MapbeanMap = new HashMap<>(); public void init() throws ServletException { super.init(); try { InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml"); //1、创建DocumentBuilderFactory DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); //2、创建DocumentBuilder对象 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); //3、创建Document对象 Document document = documentBuilder.parse(inputStream); //4、获取所有bean节点 NodeList beanNodeList = document.getElementsByTagName("bean"); for(int i = 0;i applicationContext.xml文件:
3)根据获取到的operate的值定位到FruitController中需要的方法。
先拿到所有的方法,再遍历找到和operate相同的方法
//2、根据hello对应到HelloController Object controllerBeanObj = beanMap.get(servletPath); String operate = request.getParameter("operate"); if(StringUtil.isEmpty(operate)){ operate = "index"; } try { Method[] methods = controllerBeanObj.getClass().getDeclaredMethods(); for (Method method : methods) { if (operate.equals(method.getName())) {2、调用Controller组件中的方法由以前在每个方法里获取值,优化为传入参数;
由以前在每个方法里进行服务器重定向或跳转页面,优化为返回String值,后面进行视图处理。
1)获取参数
获取即将要调用的方法的参数信息:Parameter[] parameters = method.getParameters();
通过parameter.getName()获取参数的名称;
准备Object[] parameterValues 数组用来存放对应参数的参数值;
需要考虑参数类型问题,需要做类型转化工作,parameter.getType()获取参数类型。
//1、统一获取请求参数 //获取当前方法参数,返回参数数组 Parameter[] parameters = method.getParameters(); //承载参数值 Object[] parameterValues = new Object[parameters.length]; for(int i = 0;i2)执行方法
//2、controller组件方法调用 method.setAccessible(true); Object returnObj = method.invoke(controllerBeanObj,parameterValues);3)视图处理
//3、视图处理 String methodReturnStr = (String) returnObj; if (methodReturnStr.startsWith("redirect:")) { String redirectStr = methodReturnStr.substring("redirect:".length()); response.sendRedirect(redirectStr); } else { super.processTemplate(methodReturnStr, request, response); } } } // else { // throw new RuntimeException("operate非法"); // } }catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); }
理解servlet优化对以后学习mvc会有帮助。



