JavaEE之WEB项目开发(使用Servlet+Tomcat)

一、WEB项目的演变

1.发展规律

  • 由单机向网络发展
  • 由CS向BS发展

2.CS和BS的区别

1)CS

  • Client Server
  • 客服端服务器程序
  • 客户端需要单独开发,用户需要单独下载并安装

2)BS

  • Browser Server
  • 浏览器服务器程序
  • 客户端不用单独开发,用户不用单独安装

二、Servlet介绍(*)

1.服务器如何保存并返回一个网页?

1)静态网页

  • 无论谁看其内容都一样
  • 百科、新闻
  • 服务器直接存HTML,直接返回HTML即可

2)动态网页

  • 不同人看到的内容有差异
  • 淘宝、微博
  • 服务器保存一个组件,动态给每个用户拼一个网页
  • 在Java语言中这个组件就是Servlet

组件:满足规范的对象

2.Servlet的特点

  • 是服务器端的组件
  • 满足sun的规范
  • 可以动态拼资源(HTML/IMG等)

术语:处理HTTP协议

3.什么是Servlet?

  • 是sun推出的用于在服务器端处理HTTP协议的组件

三、服务器

1.名称

  • Java服务器
  • WEB服务器
  • Java WEB服务器
  • Servlet容器

2.本质

  • 是一个软件
  • 它和浏览器是平级的关系

3.举例

  • Tomcat(Apache)
  • JBoss
  • WebLogic
  • WebSphere

四、Tomcat的使用方式

1.单独使用(项目上线时)

1)配置好JAVA_HOME

2)下载及安装

  • 去Apache官网
  • 安装配置自行百度

3)启动tomcat

  • Linux:打开/tomcat/bin,在终端输入chmod +x *sh
  • Linux:打开/tomcat/bin,在终端输入./startup.sh
  • windows:打开/tomcat/bin,双击startup.bat

4)访问tomcat

  • 在浏览器上输入http://localhost:8080
  • 回车后看到一只猫咪

5)关闭tomcat

  • Linux:打开/tomcat/bin,在终端输入./shutdown.sh
  • windows:打开/tomcat/bin,双击shutdown.bat

2.通过Eclipse调用(开发时)

  • 点击window -> preferences -> server -> Runtime Environments -> add …
  • 在Eclipse中将自动生成Servers项目

补充

1.tomcat常见使用问题

1)问题描述

  • 在启tomcat时看到如下错误
  • adress already in use,JVM_BIND:8080

2)产生的原因

  • 重复启动tomcat造成8080端口冲突
  • 可能其他软件占用了8080端口

3)解决方案

  • 启动原因:打开/tomcat/bin目录,通过命令强制关闭它
  • 其它软件:打开server.xml,在65行修改tomcat端口

建议修改为8088/8089,修改后重启tomcat才生效

五、Servlet开发步骤

1.创建WEB项目

  • 必须具备标准的WEB目录
  • /webapp/WEB-INF/web.xml

2.导入jar包

1)使用maven

  • 使用maven搜索javaee
  • 在结果中选择javaee-api

2)使用tomcat自带的包(一般使用这个)

  • 选择项目右键点击properties
  • 弹出框里在左侧选择Targeted Runtimes
  • 在右侧勾选Apache Tomcat
  • Apply

3.开发Servlet

1)编写Servlet

  • 创建package
  • 创建一个类,名为XxxServlet
  • 继承HttpServlet,从而间接的实现了Servlet接口
  • 重写父类的service()

2)配置Servlet

  • 先声明类,并给它去别名
  • 在通过别名引用此类,给他取一个访问路径

4.部署(拷贝)

  • 在Servers视图下,选择tomcat7
  • 右键点击Add and Remove
  • 在弹出框内将左边的待部署项目移动到右侧
  • 启动tomcat即可

5.访问

六、案例(浏览器显示系统时间)

这里写图片描述

目录结构

这里写图片描述

TimeServlet代码

package web;

import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TimeServlet extends HttpServlet {

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse res) 
						  throws ServletException, IOException {
		//1.使用request接收请求数据
		//1)请求行(3)
		System.out.println("协议类型:"+req.getProtocol());
		System.out.println("访问路径:"+req.getServletPath());
		System.out.println("请求方式:"+req.getMethod());
		//2)消息头(键值对)
		//该数据是按照键值对的方式存储的
		//Enumeration是一个古老的迭代器,
		//其用法和Iterator相似.
		Enumeration<String> e = req.getHeaderNames();
		while(e.hasMoreElements()) {
			String key = e.nextElement();
			String value = req.getHeader(key);
			System.out.println(key + ":" + value);
		}
		//3)实体内容
		//本案例没有传递具体的业务数据
		//2.使用response发送响应数据
		//1)状态行
		//该数据由服务器自动填充
		//2)消息头
		//消息头中的大部分数据由服务器填充,但返回的内容格式需要程序员指定
		
			
		//告诉浏览器向它发送的是什么类型的内容
		res.setContentType("text/html");
		//获取输出流,该流指向的目标是浏览器
		PrintWriter pw = res.getWriter();
		//获取服务器的时间
		//将时间拼到一个网页里给浏览器返回
		Date date = new Date();
		SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
		String now = sdf.format(date);
		//3)实体内容
		//我们输出的网页就是实体内容
		//此处偷懒,拼一个简化版的网页
		pw.println("<p>" + now + "</p>");
		//关闭输出流
		pw.close();
	}
}

web.xml配置文件代码

<!-- 配置Servlet -->
<!-- 1.声明Servlet,并给它取个别名 -->
<servlet>
	<servlet-name>time</servlet-name>
	<servlet-class>web.TimeServlet</servlet-class>
</servlet>
<!-- 2.通过别名引用Servlet,并给它取个网名(网络访问路径) -->
<servlet-mapping>
	<servlet-name>time</servlet-name>
	<!-- 网名必须以/开头 -->
	<url-pattern>/ts</url-pattern>
</servlet-mapping>

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

七、HTTP协议

1.什么是HTTP

  • 就是一个规范(w3c)
  • 规定了浏览器和服务器如何通信以及通信的数据格式

2.如何通信

  • 浏览器和服务器建立连接
  • 浏览器向服务器发送请求
  • 浏览器接受响应
  • 断开连接

一次请求一次链接,降低服务器的压力

3.数据格式

1)请求数据

  • 请求行:请求的基本信息
  • 消息头:请求数据的描述
  • 实体内容:具体的业务数据

2)响应数据

  • 状态行:响应的基本信息
  • 消息头:响应数据的描述
  • 实体内容:具体的返回数据
代码实现,见上一个案例的代码注释

4.HTTP对开发者的要求

1)不用开发者处理的地方

  • 浏览器自动打包发送请求数据
  • 服务器自动打包发送响应数据

2)需要开发者处理的地方

  • 提供具体的请求中的业务数据
  • 提供具体的响应中的返回数据
  • 通过request处理请求数据,通过response处理响应数据

要求开发者会使用request和response就行了

八、注册案例

这里写图片描述

1. 以下涉及的乱码问题的解决方法(三种)

这里写图片描述

2. RegServlet.java代码

package web;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class RegServlet extends HttpServlet {

	@Override
	protected void service(
		HttpServletRequest req, 
		HttpServletResponse res) throws ServletException, IOException {
		//采用方案三解决POST请求乱码问题(在接受数据之前)
		req.setCharacterEncoding("utf-8");
		//处理请求的一般流程
		//1.接收参数
		String name = req.getParameter("userName");
		String pwd = req.getParameter("pwd");
		String sex = req.getParameter("sex");
		String[] interests = req.getParameterValues("interest");
		
		//采用方案一解决乱码问题
		//byte[] bs = name.getBytes("iso8859-1");
		//name = new String(bs,"utf-8");
		
		//2.处理业务
		//常规的注册业务应该保存这些数据,此处就输出下
		System.out.println(name);
		System.out.println(pwd);
		System.out.println(sex);
		if(interests != null) {
			for(String interest : interests) {
				System.out.println(interest);
			}
		}
		//3.发送响应
		res.setContentType("text/html;charset=utf-8");
		PrintWriter w = res.getWriter();
		w.println("<p>ok,"+name+"</p>");
		w.close();
	}
}

3. register.html代码

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>注册</title>
</head>
<body>
	<!-- 
		1.完整路径
			http://ip:port/项目名/网名
		2.绝对路径
			格式: /项目名/网名
			举例: /servlet2/reg
		3.相对路径(*)
			当前: /servlet2/reg.html
			目标: /servlet2/reg
			二者平级,相对路径: reg
	 -->
	<form action="reg" method="post">
		<p>
			账号:<input type="text" name="userName"/>
		</p>
		<p>
			密码:<input type="password" name="pwd"/>
		</p>
		<p>
			性别:
			<input type="radio" name="sex" value="M"/><input type="radio" name="sex" value="F"/></p>
		<p>
			兴趣:
			<input type="checkbox" name="interest" value="food"/>美食
			<input type="checkbox" name="interest" value="game"/>竞技
			<input type="checkbox" name="interest" value="friend"/>社交
		</p>
		<p>
			<input type="submit" value="注册"/>
		</p>
	</form>
</body>
</html>

4. 配置文件代码

<servlet>
	<servlet-name>reg</servlet-name>
	<servlet-class>web.RegServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>reg</servlet-name>
	<url-pattern>/reg</url-pattern>
</servlet-mapping>

这里写图片描述

这里写图片描述

这里写图片描述

九、Servlet运行原理

这里写图片描述

十、请求方式

1.什么是起你去方式?

  • 就是浏览器向服务器发送数据的方式
  • 我们需要掌握众多方式中的2种:GET+POST

2.GET

  • 采用请求路径传参
  • 参数在传递过程中可见,导致隐私性差
  • 路径可以容纳的数据有限,只能传少量数据

所有的请求默认都是GET请求

3.POST

  • 采用实体内容传参
  • 参数在传递过程中不可见,隐私性好
  • 实体内容专门用来传数据,大小没有限制

在form上加method=“post”

4.观察GET和POST请求

  • 在浏览器上按快捷键F12
  • 看NetWork选项

5.GET和POST使用场景(建议)

  • 查询数据时用GET,因为通常查询条件较少
  • 提交数据(表单)时用POST,因为通常提交的数据较多。

十一、乱码解决方案

这里写图片描述

补充:

JavaBean

满足如下规范的类

  • 有包
  • 有默认的构造器
  • 实现序列化接口
  • 有get/set方法

十二、模拟查询员工案例

这里写图片描述

1. Emp.java实体类

package entity;

import java.io.Serializable;
/**
 * 建议:
 * 1.尽量使用封装类型,因为它比基本类型多了null
 * 2.使用java.sql包下的日期,因为JDBC支持这样的日期类型
 *
 */
public class Emp implements Serializable {

	private Integer empno;
	private String ename;
	private String job;
	private Double sal;
	
	public Integer getEmpno() {
		return empno;
	}
	public void setEmpno(Integer empno) {
		this.empno = empno;
	}
	public String getEname() {
		return ename;
	}
	public void setEname(String ename) {
		this.ename = ename;
	}
	public String getJob() {
		return job;
	}
	public void setJob(String job) {
		this.job = job;
	}
	public Double getSal() {
		return sal;
	}
	public void setSal(Double sal) {
		this.sal = sal;
	}
	
}

2. EmpDao.java接口

package dao;

import java.util.List;
import entity.Emp;

public interface EmpDao {

	List<Emp> findAll();
	
	void save(Emp e);
}

3. EmpDaoImpl.java

package dao;

import java.util.ArrayList;
import java.util.List;

import entity.Emp;

public class EmpDaoImpl implements EmpDao {

	public List<Emp> findAll() {
		//模拟查询所有的员工
		List<Emp> list = new ArrayList<Emp>();
		
		Emp e1 = new Emp();
		e1.setEmpno(1);
		e1.setEname("唐僧");
		e1.setJob("领导");
		e1.setSal(9000.0);
		list.add(e1);
		
		Emp e2 = new Emp();
		e2.setEmpno(2);
		e2.setEname("悟空");
		e2.setJob("职员");
		e2.setSal(5000.0);
		list.add(e2);
		
		Emp e3 = new Emp();
		e3.setEmpno(3);
		e3.setEname("八戒");
		e3.setJob("职员");
		e3.setSal(6000.0);
		list.add(e3);
		
		return list;
	}

	//模拟增加一个员工(此用于后面增加员工案例)
	public void save(Emp e) {
		System.out.println("增加了员工: " + e.getEname());
	}
}

4. FindEmpServlet.java

package web;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import dao.EmpDao;
import dao.EmpDaoImpl;
import entity.Emp;

public class FindEmpServlet extends HttpServlet {

	@Override
	protected void service(HttpServletRequest req, 
			HttpServletResponse res) 
			throws ServletException, IOException {
		//1.接收参数
		//2.处理业务(查询)
		EmpDao dao = new EmpDaoImpl();
		List<Emp> list = dao.findAll();
		//3.输出响应(表格)
		res.setContentType("text/html;charset=utf-8");
		PrintWriter w = res.getWriter();
		//当前: /EmpManager/findEmp
		//目标: /EmpManager/add_emp.html
		w.println("<a href='add_emp.html'>增加</a>");
		//上面一行用于后面增加员工案例
		w.println("<table border='1' cellspacing='0' width='40%'>");
		w.println("	<tr>");
		w.println("		<td>编号</td>");
		w.println("		<td>姓名</td>");
		w.println("		<td>职位</td>");
		w.println("		<td>薪资</td>");
		w.println("	</tr>");
		//以下是表格数据
		if(list != null) {
			for(Emp e : list) {
				w.println("<tr>");
				w.println("	<td>"+e.getEmpno()+"</td>");
				w.println("	<td>"+e.getEname()+"</td>");
				w.println("	<td>"+e.getJob()+"</td>");
				w.println("	<td>"+e.getSal()+"</td>");
				w.println("</tr>");
			}
		}
		w.println("</table>");
		w.close();
	}
	
}

5. web.xml

<servlet>
	<servlet-name>findEmp</servlet-name>
	<servlet-class>web.FindEmpServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>findEmp</servlet-name>
	<url-pattern>/findEmp</url-pattern>
</servlet-mapping>

这里写图片描述

这里写图片描述

十二、模拟增加员工案例

这里写图片描述

1. AddEmpServlet.java

package web;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import dao.EmpDao;
import dao.EmpDaoImpl;
import entity.Emp;

public class AddEmpServlet extends HttpServlet {

	@Override
	protected void service(
		HttpServletRequest req, 
		HttpServletResponse res) throws ServletException, IOException {
		
		req.setCharacterEncoding("utf-8");
		
		//1.接收参数
		String ename = req.getParameter("ename");
		String job = req.getParameter("job");
		String sal = req.getParameter("sal");
		//2.处理业务:保存员工数据
		Emp e = new Emp();
		e.setEname(ename);
		e.setJob(job);
		if(sal != null && sal.equals("")) {
			e.setSal(new Double(sal));
		}		
		EmpDao dao = new EmpDaoImpl();
		dao.save(e);
		//3.发送响应
		res.setContentType("text/html;charset=utf-8");
		PrintWriter w = res.getWriter();
		w.println("<p>保存成功</p>");
		w.close();
	}
}

2. add_emp.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>增加员工</title>
</head>
<body>
	<!-- 
		当前: /EmpManager/add_emp.html
		目标: /EmpManager/addEmp.do
	 -->
	<form action="addEmp" method="post">
		<p>
			姓名:<input type="text" name="ename"/>
		</p>
		<p>
			职位:<input type="text" name="job"/>
		</p>
		<p>
			薪资:<input type="text" name="sal"/>
		</p>
		<p>
			<input type="submit" value="保存"/>
		</p>
	</form>
</body>
</html>

3. web.xml 配置文件在加上一下代码

<servlet>
	<servlet-name>addEmp</servlet-name>
	<servlet-class>web.AddEmpServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>addEmp</servlet-name>
	<url-pattern>/addEmp</url-pattern>
</servlet-mapping>

这里写图片描述

这里写图片描述

注:此案例没连数据库,保存成功并不能真正的增加

这里写图片描述

十三、重定向

这里写图片描述

1. 修改AddEmpServlet.java

package web;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import dao.EmpDao;
import dao.EmpDaoImpl;
import entity.Emp;

public class AddEmpServlet extends HttpServlet {

	@Override
	protected void service(
		HttpServletRequest req, 
		HttpServletResponse res) throws ServletException, IOException {
		
		req.setCharacterEncoding("utf-8");
		
		//1.接收参数
		String ename = req.getParameter("ename");
		String job = req.getParameter("job");
		String sal = req.getParameter("sal");
		//2.保存员工数据
		Emp e = new Emp();
		e.setEname(ename);
		e.setJob(job);
		if(sal != null && sal.equals("")) {
			e.setSal(new Double(sal));
		}		
		EmpDao dao = new EmpDaoImpl();
		dao.save(e);
		//3.发送响应
//		res.setContentType("text/html;charset=utf-8");
//		PrintWriter w = res.getWriter();
//		w.println("<p>保存成功</p>");
//		w.close();
		//重定向到查询页面,即
		//建议浏览器自己去访问查询页面.
		//当前: /EmpManager/addEmp
		//目标: /EmpManager/findEmp
		res.sendRedirect("findEmp");
	}
}

增加员工提交后,会重定向到查询界面

十四、路径

1.什么是路径

这里写图片描述

2.URI和URL的区别

1)侠义的理解

  • 只在Java项目中理解URI和URL
  • URI:绝对路径
  • URL:完整路径

从表面上看URI包含了URL

2)广义的理解

  • 在任意的WEB项目中理解URI和URL
  • URI:资源的名称
  • URL:资源的真名

URI包含了URL

3.如何配置Servlet访问路径

1)精确匹配

  • 举例: /abc
  • 只有/abc才能访问此Servlet
  • 此Servlet只能处理这一个请求

适合规模很小的项目

2)通配符

  • 举例: /*
  • 所有的路径的都能访问此Servlet
  • 此Servlet能处理所有请求

适合一个项目只写一个Servlet

3)后缀

  • 举例: *.hi
  • 表示所有以hi为后缀的请求都能访问此Servlet
  • 此Servlet能处理多个请求

适合一个项目写少量的几个Servlet

4)配置文件web.xml

<servlet>
	<servlet-name>abc</servlet-name>
	<servlet-class>web.AbcServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>abc</servlet-name>
<!-- 1.精确定位 -->
	<!-- <url-pattern>/abc</url-pattern> -->
	<!-- 2.通配符 -->
	<!-- <url-pattern>/*</url-pattern> -->
	<!-- 3.后缀,不能以斜线开头-->
	<url-pattern>*.dung</url-pattern>
</servlet-mapping>

这里写图片描述

4. 按规范处理路径修改员工查询、增加案例

这里写图片描述

添加MianServlet.java

package web;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import dao.EmpDao;
import dao.EmpDaoImpl;
import entity.Emp;
/**
 * 路径规范:
 * 查询员工:/findEmp.do
 * 增加员工:/addEmp.do
 *
 */
public class MainServlet extends HttpServlet {

	@Override
	protected void service(HttpServletRequest req, 
			HttpServletResponse res) 
			throws ServletException, IOException {
		//获取请求路径
		String path = req.getServletPath();
		//根据规范处理路径
		if("/findEmp.do".equals(path)) {
			findEmp(req,res);
		}else if("/addEmp.do".equals(path)) {
			addEmp(req,res);
		}else {
			//该异常抛给服务器,服务器可以统一处理
			throw new RuntimeException("查无此页");
		}
	}
	
	protected void findEmp(HttpServletRequest req, 
			HttpServletResponse res) 
			throws ServletException, IOException {
		//1.接收参数
		//2.处理业务(查询)
		EmpDao dao = new EmpDaoImpl();
		List<Emp> list = dao.findAll();
		//3.输出响应(表格)
		res.setContentType("text/html;charset=utf-8");
		PrintWriter w = res.getWriter();
		//当前: /EmpManager/findEmp
		//目标: /EmpManager/add_emp.html
		w.println("<a href='add_emp.html'>增加</a>");
		w.println("<table border='1' cellspacing='0' width='40%'>");
		w.println("	<tr>");
		w.println("		<td>编号</td>");
		w.println("		<td>姓名</td>");
		w.println("		<td>职位</td>");
		w.println("		<td>薪资</td>");
		w.println("	</tr>");
		//以下是表格数据
		if(list != null) {
			for(Emp e : list) {
				w.println("<tr>");
				w.println("	<td>"+e.getEmpno()+"</td>");
				w.println("	<td>"+e.getEname()+"</td>");
				w.println("	<td>"+e.getJob()+"</td>");
				w.println("	<td>"+e.getSal()+"</td>");
				w.println("</tr>");
			}
		}
		w.println("</table>");
		w.close();
	}
	
	protected void addEmp(HttpServletRequest req, 
			HttpServletResponse res) 
			throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
		
		//1.接收参数
		String ename = req.getParameter("ename");
		String job = req.getParameter("job");
		String sal = req.getParameter("sal");
		//2.保存员工数据
		Emp e = new Emp();
		e.setEname(ename);
		e.setJob(job);
		if(sal != null && sal.equals("")) {
			e.setSal(new Double(sal));
		}		
		EmpDao dao = new EmpDaoImpl();
		dao.save(e);
		//3.发送响应
//		res.setContentType("text/html;charset=utf-8");
//		PrintWriter w = res.getWriter();
//		w.println("<p>保存成功</p>");
//		w.close();
		//重定向到查询页面,即
		//建议浏览器自己去访问查询页面.
		//当前: /EmpManager/addEmp.do
		//目标: /EmpManager/findEmp.do
		res.sendRedirect("findEmp.do");
	}
	
}

修改web.xml配置文件(之前的注释掉)

<servlet>
	<servlet-name>main</servlet-name>
	<servlet-class>web.MainServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>main</servlet-name>
	<url-pattern>*.do</url-pattern>
</servlet-mapping>

这里写图片描述

将add_emp.html中的action=“addEmp” 改成 action=“addEmp.do

这里写图片描述

这里写图片描述

十五、Servlet生命周期

这里写图片描述

示例

以下几个案例都写在了Servlet3项目里了,目录结构如下

这里写图片描述

HiServlet.java

package web;

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HiServlet extends HttpServlet {
	public HiServlet() {
		System.out.println("实例化HiServlet");
	}

	@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		System.out.println("初始化HiServlet");
	}

	@Override
	protected void service(HttpServletRequest req, 
			HttpServletResponse res) 
			throws ServletException, IOException {
		System.out.println("调用HiServlet处理请求");
	}

	@Override
	public void destroy() {
		super.destroy();
		System.out.println("销毁HiServlet");
	}	
}

web.xml配置文件

<servlet>
	<servlet-name>hi</servlet-name>
	<servlet-class>web.HiServlet</servlet-class>
	<!-- 启动时加载此servlet,中间的数字是加载的顺序。 -->
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>hi</servlet-name>
	<url-pattern>/hi</url-pattern>
</servlet-mapping>

十六、ServletConfig和ServletContext

1.它们的作用

  • 都能够读取web.xml中为Servlet预置的参数

这里写图片描述

2.它们的区别

1)config

  • config和Servlet是1对1的关系
  • Tomcat在初始化每个Servlet前会给它创建一个config
  • 调用HiServelt.init()前给他创建1个config
  • 调用HelloServlet.init()前给它创建1个config
  • 如果先给某个Servlet预置数据,使用config

2)context

  • context和Servlet是1对多的关系
  • Tomact在启动前就创建唯一的一个context
  • 所有的Servlet都可以共享这个对象中的数据
  • 如果想给多个Servlet预置数据,使用context

3.它们的应用

1)config(预置参数)

  • 假设要开发一个网页游戏,若超过人数上限则要排队
  • 登入时判断是否达到最大人数
  • 开发登录功能LoginServlet
  • 人数上限应该是一个可配置的参数maxOnline
  • 该参数由LoginServlet使用

由于该参数只是LoginServlet使用,由config读取即可

示例(登录上限)

LoginServlet.java

package web;

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LoginServlet extends HttpServlet {

	//Tomcat创建Servlet的过程:
	//LoginServlet ls = new LoginServlet();
	//ServletConfig cfg = new ServletConfig();
	//ls.init(cfg);
	//ls.service();
	
	@Override
	public void init(ServletConfig config)throws ServletException {
		super.init(config);
		String maxOnline = config.getInitParameter("maxOnline");
		System.out.println(maxOnline);
	}	
	
	@Override
	protected void service(
		HttpServletRequest req, 
		HttpServletResponse res) throws ServletException, IOException {
		//此config就是init()传入的那个
		ServletConfig cfg = getServletConfig();
		String maxOnline = cfg.getInitParameter("maxOnline");
		System.out.println(maxOnline);
		System.out.println("正在登录...");
	}	
}

web.xml

<servlet>
	<servlet-name>login</servlet-name>
	<servlet-class>web.LoginServlet</servlet-class>
	<!-- 给此servlet预置参数 -->
	<init-param>
		<param-name>maxOnline</param-name>
		<param-value>3000</param-value>
	</init-param>
</servlet>
<servlet-mapping>
	<servlet-name>login</servlet-name>
	<url-pattern>/login</url-pattern>
</servlet-mapping>

这里写图片描述

这里写图片描述

2)context(分页)

  • 软件内有很多查询功能,都带有分页功能
  • 每页显示的行数size是常量,并且可配置
  • 该数据在多个查询功能之间共用,使用context读取

示例

FindDeptServlet.java
package web;

import java.io.IOException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class FindDeptServlet extends HttpServlet {

	@Override
	protected void service(
		HttpServletRequest req, 
		HttpServletResponse res) throws ServletException, IOException {
		//tomcat启动时就会创建唯一的context,并且会调用它的方法
		//加载web.xml中的公用参数,context是全局的,任何servlet都可以使用
		ServletContext ctx = getServletContext();
		String size = ctx.getInitParameter("size");
		System.out.println(size);
		System.out.println("分页查询部门数据");
		//统计流量
		//Integer count = (Integer)ctx.getAttribute("count");
		//ctx.setAttribute("count", ++count);
		//System.out.println(count);
	}
}
FindEmpServlet.java
package web;

import java.io.IOException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class FindEmpServlet extends HttpServlet {

	@Override
	protected void service(
		HttpServletRequest req, 
		HttpServletResponse res) throws ServletException, IOException {
		ServletContext ctx = getServletContext();
		String size = ctx.getInitParameter("size");
		System.out.println(size);
		System.out.println("分页查询员工数据");
		//统计流量
		//Integer count = (Integer)ctx.getAttribute("count");
		//ctx.setAttribute("count", ++count);
		//System.out.println(count);
	}
}
web.xml
<servlet>
	<servlet-name>findDept</servlet-name>
	<servlet-class>web.FindDeptServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>findDept</servlet-name>
	<url-pattern>/findDept</url-pattern>
</servlet-mapping>

<servlet>
	<servlet-name>findEmp</servlet-name>
	<servlet-class>web.FindEmpServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>findEmp</servlet-name>
	<url-pattern>/findEmp</url-pattern>
</servlet-mapping>

<!-- 在标签外配置的参数是给所有Servlet公用的参数,它们都可以通过context读取该数据 -->
<context-param>
  	<param-name>size</param-name>
  	<param-value>20</param-value>
</context-param>

这里写图片描述

这里写图片描述

这里写图片描述

4.context的特殊用法(context可以存取变量)

  • 前提:之前使用config和context读取的是常量
  • 而context还有能力读写变量
  • 用该对象读写的变量是可以被所有Servelt共用的
  • setAttribute()/getAttribute()
  • 案例:开发流量统计功能,无论访问哪个功能,流量+1
  • 由于流量是变量,并且在多功能间共用,所以用context

这里写图片描述

示例

InitServlet.java

package web;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;

/**
 * 此类仅仅是在服务器启动时初始化参数的,
 * 不负责处理任何具体的请求.
 * 一般web项目都要1-2个这样的servlet
 */
public class InitServlet extends HttpServlet {

	@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		//tomcat启动时会优先创建context,然后在创建Servlet
		ServletContext ctx = getServletContext();
		//流量默认为0
		ctx.setAttribute("count", 0);
	}
}

将FindDeptServlet.java和FindEmpServlet.java中统计流量的注释去掉

web.xml

<!-- 没人调用可以只写一半 -->
<servlet>
	<servlet-name>init</servlet-name>
	<servlet-class>web.InitServlet</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>

这里写图片描述

5.总结

  • 当需要给Servlet预置参数时使用这样的对象
  • 若参数只给一个Servlet使用,用config
  • 若参数给多个Servlet使用,用context

十七、Servlet层次结构

1.整体结构

这里写图片描述

2.HttpServlet(我们一般重写黄色的service)

这里写图片描述

十八、Servlet线程安全问题

1.同时修改局部变量

  • 局部变量存于栈内
  • 每个线程有自己的栈帧

此时没有线程安全问题

2.同时修改成员变量

  • 成员变量存于堆内
  • 所有线程共享这样的数据

此时存在线程安全问题

3.解决方案

  • 加锁

4.案例

这里写图片描述

UpServlet.java

package web;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class UpServlet extends HttpServlet {
	
	double salary = 2000.0;

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		//synchronized(this) {
			//模拟涨薪
			salary += 100.0;
			//网络延迟
			try {
				Thread.sleep(8000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			//显示数据
			res.setContentType("text/html");
			PrintWriter out =  res.getWriter();
			out.println(salary);
			out.close();
		//}		
	}	
}

web.xml

<servlet>
	<servlet-name>up</servlet-name>
	<servlet-class>web.UpServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>up</servlet-name>
	<url-pattern>/up</url-pattern>
</servlet-mapping>

不加锁下

这里写图片描述

加锁(把UpServlet.java中的代码注释去掉)

这里写图片描述

  • 5
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的 JavaEE Web 项目开发案例: 项目名称:图书管理系统 技术栈: - 前端:HTML、CSS、JavaScript、Bootstrap - 后端:Java、Servlet、JSP、JDBC、MySQL - 开发环境:Eclipse、Tomcat、MySQL 功能: - 用户登录、注册、修改密码 - 图书的增加、删除、修改、查询 - 图书的借阅、归还 - 用户信息的修改和查询 实现步骤: 1. 创建数据库和数据表 使用 MySQL 数据库,创建一个名为 `book_management` 的数据库,然后创建三个数据表:`user`、`book` 和 `borrow`。其中,`user` 表用于存储用户信息,`book` 表用于存储图书信息,`borrow` 表用于存储图书借阅信息。 2. 创建 JavaEE 项目 使用 Eclipse IDE 创建一个 JavaEE Web 项目,然后创建以下文件夹: - `src`:用于存储 Java 源代码 - `WebContent`:用于存储 Web 页面和静态资源 3. 创建 Servlet 在 `src` 文件夹下创建一个名为 `LoginServlet` 的 Servlet 类,用于处理用户登录请求。在 `doPost` 方法中,获取用户提交的用户名和密码,然后在数据库中查询是否存在该用户。 如果存在该用户,就将用户信息存储到 `HttpSession` 中,并跳转到主页;如果不存在该用户,则返回登录页面。 4. 创建 JSP 页面 在 `WebContent` 文件夹下创建一个名为 `login.jsp` 的 JSP 页面,用于显示登录表单和处理用户登录请求。在该页面中,使用 Bootstrap 框架美化登录表单,并通过 Ajax 异步提交表单数据到 `LoginServlet`。 5. 实现其他功能 依照以上步骤,分别创建 Servlet 和 JSP 页面,实现注册、修改密码、图书的增删改查、图书借阅和归还等功能。 6. 部署项目项目打包成 WAR 文件,然后将 WAR 文件部署到 Tomcat 服务器上。在浏览器中输入网址,即可访问图书管理系统。 这是一个简单的 JavaEE Web 项目开发案例,实际开发过程中还需要处理一些细节和异常情况。希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值