一、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.访问
- 格式: http://ip:port/项目名/网名
- 例子: http://localhost:8080/servlet1/ts
六、案例(浏览器显示系统时间)
目录结构
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>