Java Language——Servlet 完全解析

Servlet 为创建基于 web 的应用程序提供了基于组件、独立于平台的方法,可以不受 CGI 程序的性能限制。Servlet 有权限访问所有的 Java API,包括访问企业级数据库的 JDBC API。一个 Servlet 其实就是一个 Java 类,并且可以通过 “请求-响应” 编程模型来访问的这个驻留在服务器内存里的 Servlet 程序。

1.Servlet的使用

1、使用 Servlet,首先继承 HttpServlet,并重写 doGet() 和 doPost() 方法:

import javax.servlet.http.HttpServlet;
public class UploadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
    }
}

然后在 web.xml 中注册 Servlet 即可:

<servlet>
    <servlet-name>upload</servlet-name>
    <servlet-class>com.example.servlet.UploadServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>upload</servlet-name>
    <!-- 访问路径地址 -->
    <url-pattern>/servlet/upload</url-pattern>
</servlet-mapping>

2、Servlet 执行流程

以 post 请求为例,执行流程如下:

  1. 用户请求 Servlet URL 地址,服务器就会在 web.xml 中寻找与之对应的 url-pattern;
  2. 再根据 servlet-name 寻找与之对应的处理类;
  3. 再根据用户提交的请求方式去执行相应的 doPost()。

3、Servlet 的生命周期

  1. 初始化阶段,判断 Servlet 实例是否存在,若不存在则调用构造方法装载 Servlet 类并创建实例,然后调用init()方法,若存在执行第二步;
  2. 响应客户端请求阶段,调用service(ServletRequest req, ServletResponse res)方法根据提交方式选择执行doGet()或者doPost()方法;
  3. 服务器关闭,调用destroy()的方法。

注意:在 Servlet 的整个生命周期,init() 方法只被调用一次。

4、Tomcat 装载 Servlet 的三种情况

  • Servlet 容器启动时自动装载某些 Servlet,实现它只需要在 web.xml 文件中添加:
<servlet>
    <servlet-name>upload</servlet-name>
    <servlet-class>com.example.servlet.UploadServlet</servlet-class>
    <!-- 数字越小优先级越高 -->
    <load-on-startup>1</load-on-startup>
</servlet>
  • 在 Servlet 容器启动后,客户端首次向 Servlet 发送请求时装载 Servlet;
  • Servlet 类文件被更新后,重新装载 Servlet。

当 Servlet 被装载后,它就会长期保存在服务器的内存中。

5、Servlet 九大内置对象

内置对象Servlet 获取方式
outresp.getWriter();
requestreq 参数
responseresp 参数
sessionreq.getSession();
applicationgetServletContext();
Pagethis
pageContextPageContext
exceptionThrowable
configgetServletConfig();

6、Servlet 获取表单数据

在 doGet() 或者 doPost() 方法中获取表单数据:

String username = req.getParameter("username");
String password = req.getParameter("password");
SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-DD");
Date birthday = sdf.parse(req.getParameter("birthday"));
String[] favorites = req.getParameterValues("favorites");

7、Servlet 获取初始化参数

在 web.xml 中配置 Servlet 时,可以配置一些初始化参数。而在 Servlet 中可以通过 ServletConfig 接口提供的方法来取得这些参数。

<servlet>
    <servlet-name>upload</servlet-name>
    <servlet-class>com.example.ssm.DemoServlet</servlet-class>
    <!-- 配置初始化参数 -->
    <init-param>
        <param-name>username</param-name>
        <param-value>admin</param-value>
    </init-param>
    <init-param>
        <param-name>password</param-name>
        <param-value>123</param-value>
    </init-param>
</servlet>

就可以在 Servlet 中通过下面来获取初始化参数:

public class UploadServlet extends HttpServlet {
    @Override
	public void init() throws ServletException {
	    String username = this.getInitParameter("username");
	    String password = this.getInitParameter("password");
	}
	//代码省略
}

8、Servlet 2.5 下监听器的使用

监听器是指专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监听的对象发生变化,立即采取相应的行动。Web 监听器是 Servlet 规范中定义的一种特殊的类,包含 ServletContext、HttpSession 和 ServletRequest 的事件监听器对象,具体如下:

域对象监听域对象创建和销毁的事件监听器监听域对象中的属性的增加、删除和替换的事件监听器说明对应Servlet内置对象主要用途
ServletContextServletContextListenerServletContextAttributeListener用于监听应用程序环境application定时器、全局属性对象
HttpSessionHttpSessionListenerHttpSessionAttributeListener用于监听用户会话session统计在线人数、记录访问日志
ServletRequestServletRequestListenerServletRequestAttributeListener用于监听请求消息request读取参数、记录访问历史

下面我们以 ServletContext 为例创建一个监听器:

创建一个实现监听器接口的类:

public class MyServletContextListener implements ServletContextListener {
	//ServletContextEvent可以获取ServletContext和一些初始化参数
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("当前应用已经创建");
    }
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("当前应用已经销毁");
    }
}

配置 web.xml 进行注册(在 web-app 节点下配置):

<!-- 监听器启动优先顺序: 监听器 > 过滤器 > Servlet -->
<listener>
	<listener-class>com.example.listener.MyServletContextListener</listener-class>
</listener>

定义的顺序也就是监听器的顺序。

9、Servlet 3.0下监听器的使用

Servlet 3.0 只需要把 web.xml 中 Servlet 版本修改为 3.0 即可:

<web-app version="3.0" ...>
	...
</web-app>

使用比较简单,只需要添加 @WebListener 注解即可(不需要在 web.xml 中注册了),该注解用于将类声明为监听器,被 @WebListener 标注的类必须实现以下至少一个接口(无法去定义监听器的顺序):

ServletContextListener
ServletContextAttributeListener
HttpSessionListener
HttpSessionAttributeListener
ServletRequestListener
ServletRequestAttributeListener
@WebListener("This is only a demo listener")
public class MyServletContextListener implements ServletContextListener {
	//ServletContextEvent可以获取ServletContext和一些初始化参数
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("当前应用已经创建");
    }
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("当前应用已经销毁");
    }
}

@WebListener 的常用属性:

属性名类型是否可选描述
valueString该监听器的描述信息

2.MVC模式

MVC模式(Model、View、Conntroller)是软件开发过程中比较流行的设计思想,旨在分离模型、控制、视图,是一种分层思想的体现。

MVC模式

3.Servlet案例

使用 Servlet 实现购物车效果,下面看一下核心部分的实现:

商品类:

public class Items {
	private int id, price, number; // 商品编号,价格,库存
	private String name, city, picture; // 商品名称,产地,商品图片
	// 保留此不带参数的构造方法
	public Items() {
	}
	public Items(int id,String name,String city,int price,int number,String picture) {
		this.id = id;
		this.name = name;
		this.city = city;
		this.picture = picture;
		this.price = price;
		this.number = number;
	}
	// 保证不添加重复商品进购物车需要重写hashCode方法和equals方法
	@Override
	public int hashCode() {
		return this.getId()+this.getName().hashCode();
	}
	/**
	 * @param obj 商品对象
	 * @return 已经存在返回true
	 */
	@Override
	public boolean equals(Object obj) {
		if(this==obj) {
			return true;
		}
		if(obj instanceof Items) {
			Items i = (Items)obj;
			if(this.getId()==i.getId()&&this.getName().equals(i.getName())) {
				return true;
			} else {
				return false;
			}
		} else {
			return false;
		}
	}
	// 省略setter、getter、toString方法
}

购物车类:

public class Cart {
	private HashMap<Items,Integer> goods; // 购买商品的集合
	private double totalPrice; // 购物车的总金额
	// 构造方法
	public Cart() {
		goods = new HashMap<Items,Integer>();
		totalPrice = 0.0;
	}
	/**
	 * 添加商品进购物车的方法
	 * @param item 购买的商品对象
	 * @param number 购买的商品数量
	 * @return
	 */
	public boolean addGoodsInCart(Items item ,int number) {
		if(goods.containsKey(item)) { // 如果goods包含此item的映射关系,则返回 true
			goods.put(item, goods.get(item)+number);
		} else {
			goods.put(item, number);	
		}
		calTotalPrice(); // 重新计算购物车的总金额
		return true;
	}
	/**
	 * 删除商品的方法
	 * @param item 删除的商品对象
	 * @return
	 */
	public boolean removeGoodsFromCart(Items item) {
		goods.remove(item);
		calTotalPrice(); // 重新计算购物车的总金额
		return true;
	}
	/**
	 * 统计购物车的总金额
	 * @return
	 */
	public double calTotalPrice() {
		double sum = 0.0;
		Set<Items> keys = goods.keySet(); // 获得键的集合
		Iterator<Items> it = keys.iterator(); // 获得迭代器对象
	    while(it.hasNext()) {
	    	Items i = it.next();
	    	sum += i.getPrice()* goods.get(i);
	    }
	    this.setTotalPrice(sum); // 设置购物车的总金额
	    return this.getTotalPrice();
	}
	// 省略setter、getter、toString方法
}

编写 Servlet:

public class CartServlet extends HttpServlet {
	private String action; // 表示购物车的动作 add,show,delete
	private ItemsDAO idao = new ItemsDAO(); // 商品业务逻辑类的对象
	private static Logger logger = Logger.getLogger(CartServlet.class);

	public CartServlet() {
		super();
	}
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		doPost(req,resp); // 方便测试
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		resp.setContentType("text/html;charset=utf-8");
		PrintWriter out = resp.getWriter();
		if(req.getParameter("action")!=null) {
			this.action = req.getParameter("action");
			logger.info(action.toString());
			if(action.equals("add")) { // 如果是添加商品进购物车
				if(addToCart(req,resp)) {
					req.getRequestDispatcher("/success.jsp").forward(req, resp);
				} else {
					req.getRequestDispatcher("/failure.jsp").forward(req, resp);
				}
			}
			if(action.equals("show")) { // 如果是显示购物车
				req.getRequestDispatcher("/cart.jsp").forward(req, resp);
			}
			if(action.equals("delete")) { // 如果是执行删除购物车中的商品
				if(deleteFromCart(req,resp)) {
					req.getRequestDispatcher("/cart.jsp").forward(req, resp);
				} else {
					req.getRequestDispatcher("/cart.jsp").forward(req, resp);
				}
			}
		}
	}
	// 添加商品进购物车的方法
	private boolean addToCart(HttpServletRequest request, HttpServletResponse response) {
		String id = request.getParameter("id");
		String number = request.getParameter("num");
		Items item = idao.getItemsById(Integer.parseInt(id));
		logger.info("id=" + id + ", number=" + number);
		// 是否是第一次给购物车添加商品,需要给session中创建一个新的购物车对象
		if(request.getSession().getAttribute("cart")==null) {
			Cart cart = new Cart();
			request.getSession().setAttribute("cart",cart);
		}
		Cart cart = (Cart)request.getSession().getAttribute("cart");
		if(cart.addGoodsInCart(item, Integer.parseInt(number))) {
			return true;
		} else {
			return false;
		}
		return false;
	}
	// 从购物车中删除商品
	private boolean deleteFromCart(HttpServletRequest request, HttpServletResponse response) {
		String id = request.getParameter("id");
		Cart cart = (Cart)request.getSession().getAttribute("cart");
	    Items item = idao.getItemsById(Integer.parseInt(id));
	    if(cart.removeGoodsFromCart(item)) {
	    	return true;
	    } else {
	    	return false;
	    }
		return false;
	}
}

在 web.xml 中注册 Servlet:

<servlet>
    <servlet-name>cart</servlet-name>
    <servlet-class>com.example.servlet.CartServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>cart</servlet-name>
    <!-- 访问路径地址 -->
    <url-pattern>/servlet/cart</url-pattern>
</servlet-mapping>

编写 Dao:

//商品的业务逻辑类
public class ItemsDAO {
	//获得所有的商品信息
	public ArrayList<Items> getAllItems() {
		//省略数据库操作代码
	}
	// 根据商品编号获得商品资料
	public Items getItemsById(int id) {
		// 省略数据库操作代码
	}
	// 获取最近浏览的前五条商品信息
	public ArrayList<Items> getViewList(String list) {
		ArrayList<Items> itemlist = new ArrayList<Items>();
		int iCount=5; // 每次返回前五条记录
		if(list!=null&&list.length()>0) {
		    String[] arr = list.split(",");
		    // 如果商品记录大于等于5条
		    if(arr.length>=5) {
		       for(int i=arr.length-1;i>=arr.length-iCount;i--) {
		    	  itemlist.add(getItemsById(Integer.parseInt(arr[i])));  
		       }
		    } else {
		    	for(int i=arr.length-1;i>=0;i--) {
		    		itemlist.add(getItemsById(Integer.parseInt(arr[i])));
		    	}
		    }
		    return itemlist;
		} else {
			return null;
		}
	}
}

最后测试购物车功能,访问 http://localhost:8080/servlet/cart?id=2&num=4&action=add,发现已经成功添加商品。

  • 15
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值