对 Servlet 的改进--------Struts2 引入

  通过上一篇博客:Servlet 的详解 https://cloud.tencent.com/developer/article/1012709,我们大致知道了 Servlet 的基本用法。但是稍微分析一下 Servlet 的用法,我们还是发现其存在很多缺点:

  ①、一个请求对应一个 Servlet,即每一个请求我们都需要在 web.xml 文件中配置映射。如果项目大,请求很多,那么会造成 web.xml 很大,很难维护。

  ②、即便在好几个请求对应一个 Servlet,即在 service() 方法中,通过 if--else 语句来判断执行的代码块。那这样就会造成 service() 方法很拥挤。

  ③、一个项目只存在一个 web.xml 文件,如果一个项目是多人开发,那么整合代码开发过程中会有很多问题。不适合团队开发。

  ④、Servlet中doGet方法和doPost方法中的两个参数reqeust,response拥有严重的容器依赖性。

  ⑤、如果页面上表单中的元素比较复杂,则在Servlet的方法中获取表单元素的数据比较繁琐。

  ⑥、Servlet是单线程的,只要在Servlet中的声明一个实例变量,那么该变量在多线程访问时就会有线程安全问题。

  ⑦、在Servlet中处理异常,如果Servlet中有N个方法,则这N个方法必须都要try--catch。因为子类抛的异常不能大于父类。

那么接下来我们用一个例子来解决上面的问题。

  1、新建一个 Web 工程,名为 ServletIncreased。并在 web.xml 中配置一个过滤器 ServletFilter,这个过滤器会过滤所有以 .do 结尾的 URL 链接

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://java.sun.com/xml/ns/javaee"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
  http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
   id="WebApp_ID" version="3.0">
   
  <filter>
    <filter-name>ServletFilter</filter-name>
    <filter-class>com.ys.filter.ServletFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>ServletFilter</filter-name>
    <url-pattern>*.do</url-pattern>
  </filter-mapping>
  
</web-app>

  2、创建一个 UserServlet,里面有两个方法,insert()和update()方法,调用 insert() 方法会跳转到 insert.jsp 页面,调用 update() 方法会调转到 update.jsp 页面

package com.ys.servlet;

import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class UserServlet {
	//用户插入方法
	public void insert(HttpServletRequest req,HttpServletResponse resp) throws Exception, IOException{
		req.getRequestDispatcher("insert.jsp").forward(req, resp);
	}
	
	//用户更新方法
	public void update(HttpServletRequest req,HttpServletResponse resp) throws Exception, IOException{
		req.getRequestDispatcher("update.jsp").forward(req, resp);
	}
	
}

  3、创建一个配置文件类,里面存放配置文件的关系,通过一个 Map 集合,保存 Servlet 的类名和全类名

package com.ys.config;

import java.util.HashMap;
import java.util.Map;

public class ServletNameConfig {
	//定义一个 Servlet 配置文件,Map<key,value>
	//key:表示 Servlet 的类名
	//value:表示 Servlet 类名的全称
	public static Map<String, String> servletMap = new HashMap<>();
	
	static {
		servletMap.put("UserServlet", "com.ys.servlet.UserServlet");
	}

}

  4、回头看我们配置的过滤器,ServletFilter

package com.ys.filter;

import java.io.IOException;
import java.lang.reflect.Method;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ys.config.ServletNameConfig;

public class ServletFilter implements Filter{
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse resp = (HttpServletResponse) response;
		
		String reqURL = req.getRequestURI(); //  /ServletIncreased/UserServlet.do
		String[] strs = reqURL.split("/");
		//定义 Servlet 的全类名
		String servletAllName = null;
		if(strs[2] != null){
			//得到 请求路径的 servlet 类名
			String servletName = strs[2].substring(0, strs[2].indexOf("."));
			//根据获取的 Servlet 类名,由配置文件 ServletNameConfig 里面的map 得到 全类名
			servletAllName = ServletNameConfig.servletMap.get(servletName);
		}
		//获取请求方法名
		String methodName = req.getParameter("method");
		System.out.println(servletAllName+"---"+methodName);
		try {
			//通过反射调用执行方法
			Class obj = Class.forName(servletAllName);
			Method method = obj.getDeclaredMethod
					(methodName, HttpServletRequest.class,HttpServletResponse.class);
			method.invoke(obj.newInstance(), req,resp);
		} catch (Exception e) {
			e.printStackTrace();
		}		
	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
	}
	@Override
	public void destroy() {
	}

}

  整体的项目结构如下:

然后将整个项目发布到 tomcat 服务器运行,发布的方法可以如下:

https://cloud.tencent.com/developer/article/1012658

然后我们在浏览器输入如下链接:http://localhost:8080/ServletIncreased/UserServlet.do?method=insert

  那么就会调用 UserServlet 的 insert 方法,进而跳转到 insert.jsp 页面

如果我们在浏览器输入如下链接:将 insert 改为 update

   http://localhost:8080/ServletIncreased/UserServlet.do?method=update

那么就会调用 UserServlet 的update 方法,进而调转到 update.jsp 页面

分析:这个改进主要是配置了一个过滤器,然后通过过滤器的 doFilter() 方法,我们可以通过请求路径获得请求URL,然后通过字符串的截取方法得到 Servlet 的名称。通过配置文件保存的 Servlet类名和全类名的对应关系得到全类名;然后利用反射的原理,通过 invoke() 方法来动态调用方法。这里我们并没有解决上面所有的问题,比如严重的容器依赖性我们这里还有。如果想真正解决,请看下一篇博客:Struts2 详解

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏WindCoder

RequestParam与RequestBod等参数注解简析

该注解常用来处理Content-Type: 不是application/x-www-form-urlencoded和multipart/form-data编码的...

341
来自专栏me的随笔

使用AutoMapper进行对象间映射

在开发过程中,难免遇到下面这种情况:两个(或多个)对象所拥有的大多数属性是重复的,我们需要在对象间进行映射(即将一个对象的属性值赋给另一个对象。通常我们可以进行...

882
来自专栏IT可乐

Servlet 详解

1、什么是 Servlet? Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请...

1837
来自专栏菩提树下的杨过

ExtJs学习笔记(23)-ScriptTagProxy+XTemplate+WCF跨域取数据

ajax应用中跨域一直是一个非常麻烦的问题,目前也有一些解决办法,但要么比较麻烦,要么就不具备通用性,幸好ExtJs里的ScriptTagProxy提供了跨域读...

1928
来自专栏LanceToBigData

struts2(五)之struts2拦截器与自定义拦截器

前言   前面介绍了struts2的输入验证,如果让我自己选的话,肯定是选择xml配置校验的方法,因为,能使用struts2中的一些校验规则,就无需自己编写了,...

2175
来自专栏一个会写诗的程序员的博客

8.1 Spring Boot集成Groovy混合Java开发小结

本章节我们使用SpringBoot集成Groovy混合Java开发一个极简的RestAPI。 数据库使用mysql,ORM层使用mybatis,模板引擎使用fr...

702
来自专栏A周立SpringCloud

Spring Cloud Zuul过滤器详解

开端 阅读本文,您将了解: (1) Zuul过滤器类型与请求生命周期 (2) 如何编写Zuul过滤器 (3) 如何禁用Zuul过滤器 (4) Spring Cl...

4045
来自专栏跟着阿笨一起玩NET

用于RichTextBox控件记录日志信息

471
来自专栏c#开发者

Asp.net Dynamic Data之三改变编辑和操作数据的现实方式

Asp.net Dynamic Data之三改变编辑和操作数据的现实方式 本专题介绍如何运用RouteCollection 添加或是修改Routing URL...

4038
来自专栏LanceToBigData

struts2(五)之struts2拦截器与自定义拦截器

  前面介绍了struts2的输入验证,如果让我自己选的话,肯定是选择xml配置校验的方法,因为,能使用struts2中的一些校验规则,就无需自己编写了,

511

扫码关注云+社区