注:自动添加protected void service(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException { 的方法步骤
右键空白处-source-Override/Implement Methods...-getLastModifed(....)
如果复制粘贴servlet项目,别先部署,需要右键项目名-Properties-web Project Settings-Context root: 名称更改为和现名称一样。。
如果先部署了 会导致服务器运行报错, 这种情况需删除粘贴的项目 部署复制项目后在重新粘贴。
# 1.什么是Servlet?
sun公司制订的一种用来扩展web服务器功能的组件规范。
![](s1.png)
## (1)扩展web服务器功能
web服务器只能够处理静态资源的请求(即需要事先将
静态页面写好),不能够处理动态资源的请求(即需要进行计算,生成动态页面),所以,需要扩展其功能。
可以使用Servlet来扩展web服务器功能,web服务器收到
请求之后,如果需要计算,则调用Servlet来处理。
## (2)组件规范
### 1)什么是组件?
符合规范、实现部分功能,并且需要部署到相应的容器当中才能运行的软件模块。
Servlet是一个组件,必须符合Servlet规范,并且需要部署到Servlet容器当中才能运行。
### 2)什么是容器?
符合规范、提供组件运行环境的程序。
Servlet容器(比如Tomcat)为Servlet提供运行环境
(主要是提供网络相关的服务)
# 2.如何写一个Servlet?
step1.写一个java类,实现Servlet接口或者继承HttpServlet。
step2.编译。
step3.打包。(即建立一个具有如下结构的文件夹)
appname
WEB-INF(自定义名字)
classes (放.class文件)
lib (可选,放.jar文件)
web.xml (部署描述文件)
step4.部署。
把step3创建好的文件夹拷贝到容器指定的位置。
注:
可以将step3创建好的文件夹压缩成".war"为后缀
的文件,然后拷贝。
step5.启动容器,访问Servlet。
http://ip:port/appname/url-pattern
注:
url-pattern在web.xml中设置。
# 3.Servlet是如何运行的?
比如,在浏览器地址栏输入http://localhost:8080/day01/hello
![](s2.png)
step1.浏览器依据ip和port建立连接。
step2.浏览器将相关数据放到请求数据包,然后将请求
数据包发送给服务器。
step3.服务器解析请求数据包,将解析到的结果放到
request对象里面,同时,创建一个response对象。
step4.服务器依据请求路径,创建Servlet对象,然后
调用该对象的service方法。
注:
开发人员只需要调用request对象的方法,就
可以获得请求数据包中的数据。类似的,只需要调用
response对象的方法,就可以将处理结果写到
response对象里面,容器会从response对象中取
出处理结果,然后创建响应数据包并发送给浏览器。
step5.容器从response对象中取出处理结果,然后创建
响应数据包并发送给浏览器。
step6.浏览器解析响应数据包,生成结果页面。
# 4.常见错误
## (1)404
a.含义:服务器依据请求路径,找不到对应的资源。
b.错误原因:
b1.请求路径写错。
b2.应用没有部署或者部署失败。
## (2)500
a.含义:服务器端程序运行发生问题。
b.错误原因:
b1.没有严格按照规范来写代码。
比如,没有继承HttpServlet或者实现Servlet
接口。又或者部署描述文件写错。
b2.代码写得不严谨。
比如,对请求参数值没有做任何检查就直接做类型
转换。
## (3)405
a.含义:服务器找不到处理方法。
b.错误原因:
没有正确override HttpServlet的service方法。
# 练习:
写一个Servlet(比如DateServlet),输出当前的
系统日期,比如"2018-10-25"
## 提示
## step1.创建一个maven工程。注意三个细节:
细节1:选war包,如下图所示:
![](a1.png)
细节2:工程建完之后,默认没有带web.xml文件,需要
添加web.xml文件,如下图所示:
![](a2.png)
细节3:指定servlet容器,如下图所示:
![](a3.png)
## step2.添加一个java类(DateServlet)
参考代码如下:
public class DateServlet extends HttpServlet{
public void service(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException,IOException{
//生成日期信息
Date date = new Date();
SimpleDateFormat sdf =
new SimpleDateFormat("yyyy-MM-dd");
String dateInfo =
sdf.format(date);
//输出日期
response.setContentType("text/html");
PrintWriter out =
response.getWriter();
out.println(dateInfo);
out.close();
}
}
## step3. 在web.xml添加该Servlet的配置
参考配置如下:
<servlet>
<servlet-name>dateServlet</servlet-name>
<servlet-class>web.DateServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dateServlet</servlet-name>
<url-pattern>/date</url-pattern>
</servlet-mapping>
## step4.部署、运行
![](a4.png)
## Tomcat的配置请参考doc.tedu.cn上的文档。
![](a5.png)
# 课后练习
写一个Servlet,计算一个人的BMI指数。
BMI指数 = 体重(公斤) / 身高(米) / 身高(米)
—————————————————————————————————
# 1.http协议 (了解)
## (1)什么是http协议?
是一种网络应用层协议、规定了浏览器与web服务器之间如何
通信以及相应的数据包的格式。
### 1)如何通信?
step1.建立连接
step2.发送请求
step3.发送响应
step4.关闭连接
这样做的好处是,服务器可以利用有限的连接数为尽可能
多的请求服务。
![](http.png)
### 2)数据包的格式
a.请求数据包
请求行(请求方式 请求资源路径 协议和版本)
若干消息头
消息头是一些键值对,使用": "隔开,通信的
双方可以借助于消息头来传递一些特定的信息,比如
浏览器可以发送"user-agent"消息头,告诉服务器
浏览器的类型和版本。
实体内容
如果请求类型为get,实体内容为空。
只有当请求类型为post时,实体内容才会有数据。
b.响应数据包
状态行(协议类型和版本 状态码 状态描述)
注:
状态码是一个三位数字,表示服务器处理请求
的一种状态,常见状态码如下:
200: 正常
500: 系统出错
404: 请求路径出错
若干消息头
服务器也可以发送一些消息头给浏览器,比如,发送
content-type消息头,告诉浏览器,服务器返回的数据类型(包括编码)
c.实体内容
程序的处理结果,浏览器会解析出来,生成相应的页面。
## (2)两种请求方式
### 1)哪些情况下,浏览器会发送get请求?
a.直接在浏览器地址栏输入地址。
b.点击链接。
c.表单的默认提交方式。
### 2)get请求的特点
a.会将请求参数显示在浏览器地址栏,不安全。
注:
因为有些网络设置(比如路由器)会记录访问地址。
b.会将请求参数添加到请求资源路径的后面,只能提交
少量的数据给服务器。
注:
因为请求行大约只能存放2k左右的数据。
## 3)哪些情况下,浏览器会发送post请求
a.设置表单的method属性值为"post"。
## 4)post请求的特点
a.不会将请求参数显示在浏览器地址栏,相对安全。
注:
http协议并不会对数据进行加密,所以,对于
敏感数据,需要进行加密处理(使用https协议)。
b.将请求参数添加到了实体内容里面,可以提交大量的
数据给服务器。
# 2.Servlet输出中文需要注意的问题
## (1)为什么会产生乱码?
因为out.println方法默认会使用"iso-8859-1"来编码。
## (2)如何解决?
response.setContentType("text/html;charset=utf-8");
# 3.读取请求参数值
## (1)String getParameter(String paramName)
a.请求参数名(paramName)要与实际传递过来的请求
参数名一致,否则会获得null值。
b.提交表单时,如果不填写任何数据,会获得 ""。
## (2)String[] getParamterValues(String paramName)
a.当有多个请求参数名相同时,使用此方法。
b.对于多选框,如果不选择任何选项,会获得null值
#4.表单包含有中文参数值,如何处理?
##1)为什么会产生乱码?
提交表单时,浏览器会对表单中的中文的中文参数值进行编码,比如 使用utf-8来编码,服务器端默认会使用iso-8859-1来节码,所以会产生乱码。
注:浏览器会按照打开表单所在页面时的字符集来编码。
##(2)如何解决?
###1)post请求:
request.setCharacterEncoding("utf-8);
注:此行代码要添加到所有的getParameter方法的最前面。
只针对post请求有效
###2)get请求:
修改tomcat的配置文件(Servers-Tomcat...-server.xml)
<Connector URIEncoding="utf-8"/>
注:只针对get请求有效
#5.访问数据库
step1.导包
jdbc驱动,连接池
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
stp2.添加jdbc.properties文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jsd1807db? useUnicode=true&characterEncoding=UTF-8
username=root
password=root
step3.添加DBUtils类。
public class DBUtils {
private static String driver;
private static String url;
private static String username;
private static String password;
private static BasicDataSource dataSource;
static {
Properties prop = new Properties();
InputStream ips = DBUtils.class
.getClassLoader()
.getResourceAsStream("jdbc.properties");
try {
prop.load(ips);
driver = prop.getProperty("driver");
url = prop.getProperty("url");
username = prop.getProperty("username");
password = prop.getProperty("password");
//创建数据源对象
dataSource =
new BasicDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setInitialSize(3);
dataSource.setMaxActive(3);
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
ips.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static Connection getConn()
throws Exception {
return dataSource.getConnection();
}
public static void close(Connection conn,
Statement stat, ResultSet rs) {
try {
if(rs!=null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(stat!=null) {
stat.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(conn!=null) {
//打开自动提交
conn.setAutoCommit(true);
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
step4.添加一张表(t_user)
create table t_user(
id int primary key auto_increment,username varchar(50) unique,
password varchar(20),email varchar(30));
step5.在service方法里面,使用jdbc api 访问数据库
public class AddUserServlet extends HttpServlet{
@Override
protected void service(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException,
IOException {
//处理表单中文参数值的问题
request.setCharacterEncoding("utf-8");
/*
* 这行代码的作用:
* 1.设置content-type消息头的值。
* 2.out.println方法在输出时,会使用
* charset指定的字符集来编码。
*/
response.setContentType(
"text/html;charset=utf-8");
PrintWriter out =
response.getWriter();
//读取用户信息
String username =
request.getParameter("username");
String pwd =
request.getParameter("pwd");
String email =
request.getParameter("email");
//将用户信息插入到数据库
Connection conn = null;
PreparedStatement ps = null;
try {
conn = DBUtils.getConn();
String sql = "INSERT INTO t_user "
+ "VALUES(null,?,?,?)";
ps = conn.prepareStatement(sql);
ps.setString(1, username);
ps.setString(2, pwd);
ps.setString(3, email);
ps.executeUpdate();
out.println("添加成功");
} catch (Exception e) {
/*
* step1.记日志(保留现场)
* 注:
* 在实际项目中,经常需要将异常
* 信息写到文件里面。
*/
e.printStackTrace();
/*
* step2.看异常能否恢复,如果
* 异常不能够恢复(比如数据库服务
* 停止、网络中断等等,这样的异常
* 我们一般称之为系统异常),则提示
* 用户稍后重试;
* 如果能够恢复,则立即恢复。
*/
out.println("系统繁忙,稍后重试");
}finally {
DBUtils.close(conn, ps, null);
}
}
}
注:自动添加protected void service(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException { 的方法步骤
右键空白处-source-Override/Implement Methods...-getLastModifed(....)
—————————————————————————————————
# 1.重定向
## (1)什么是重定向?
服务器通知浏览器向某个地址发送请求。
注:
服务器可以发送302状态码和Location消息头
(该消息头的值是一个地址,一般称之为重定向
地址)给浏览器,浏览器收到之后,会立即向
重定向地址发送请求。
![](redirect.png)
## (2)如何重定向?
response.sendRedirect(String url);
注:
url是重定向地址。
容器在重定向之前,会清空response对象上存放的
所有数据。
## (3)特点
a.重定向之后,浏览器地址栏的地址会发生改变。
b.重定向的地址是任意的。
# 2. DAO (Data Access Object)
## (1)DAO是什么?
是一个封装了数据访问逻辑的对象。
## (2)如何写一个DAO?
step1.写一个java类(一般称之为实体类)。
注:
该类与要访问的表的结构保持一致,即
表有哪些字段,该类要有与之对应的属性,属性
类型要与表的字段类型匹配。
我们可以将记录中保存的信息添加到实体对象
里面,方便处理。
public class User {
private int id;
private String username;
private String pwd;
private String email;
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", pwd=" + pwd + ", email=" + email + "]";
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
step2.写一个java类,提供一些访问数据库的方法。
public class UserDAO {
/**
* 查询出所有用户的信息。
* 注:
* 关系数据库里面存放的是一条条记录,
* 而java是面向对象的语言。在设计
* DAO时,我们经常将查询到的记录转换成
* 一个对应的java对象。
*/
public List<User> findAll()
throws Exception{
List<User> users =
new ArrayList<User>();
Connection conn = null;
PreparedStatement stat = null;
ResultSet rs = null;
try {
conn = DBUtils.getConn();
String sql =
"SELECT * FROM t_user";
stat = conn.prepareStatement(sql);
rs = stat.executeQuery();
while(rs.next()) {
int id = rs.getInt("id");
String username =
rs.getString("username");
String pwd =
rs.getString("password");
String email =
rs.getString("email");
User user = new User();
user.setId(id);
user.setUsername(username);
user.setPwd(pwd);
user.setEmail(email);
users.add(user);
}
} catch (Exception e) {
e.printStackTrace();
throw e;
}finally {
DBUtils.close(conn, stat, rs);
}
return users;
}
}
## 3)DAO的优点
a.DAO封装了数据访问逻辑,调用者不用关心数据访问逻辑是
如何实现的。这样,代码更好维护。
b.方便测试。如果将数据访问写在servlet里面,需要部署
整个应用才能测试。
—————————————————————————————————
# 1.jsp
## (1)jsp是什么?
sun公司制订的一种服务器端动态页面技术规范。
注:
虽然使用Servlet也可以生成动态页面,但是过于
繁琐(需要使用out.println语句),并且不利于页面的
维护(比如,要修改页面就必须修改java代码),所以,sun
才制订了jsp技术规范。
jsp其实是一个以.jsp为后缀的文件,主要内容是
html和少量的java代码。容器会将jsp文件转换成一个对应的servlet然后执行。
jsp的本质就是一个servlet。
## (2)如何写一个jsp文件?
step1. 添加一个以.jsp为后缀的文件。
step2. 在该文件里面,可以使用如下元素:
### 1)html(css,javascript)
直接写即可。
### 2)java代码
方式一 java代码片断
<% java代码 %>
方式二 jsp表达式
<%= java表达式 %>
### 3)隐含对象
a.什么是隐含对象?
直接可以使用的对象,比如out、request、response。
b.为什么可以直接使用这些隐含对象?
因为容器会自动添加获得这些对象的语句。
### 4)指令
a.什么是指令?
通知容器,在将jsp文件转换成一个Servlet类时,
做一些的额外的处理,比如导包。
b.指令的语法
<%@ 指令名 属性=值 %>
c.page指令
import属性:用于指定要导的包名。
比如
<%@ page import="java.util.*,java.text.*"%>
## (3)jsp是如何执行的?
### 1)阶段一 容器将.jsp文件转换成一个Servlet类。
html(css,js) ----> service方法里面,使用out.write输出。
<% %> -----> service方法里面,照搬。
<%= %> -----> service方法里面,使用out.print输出。
### 2)阶段二 容器调用该Servlet
需要编译、实例化、然后调用service方法。
# 练习 写一个date.jsp,输出当前的系统日期,比如
<%@ page import="java.util.*,java.text.*" %>
<html>
<head></head>
<body style="font-size:30px;">
<%
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
%>
<%=sdf.format(date) %>
</body>
</html>
输出 "2018-10-31"
—————————————————————————————————
编写程序,找出101到200自然数中的质数,for循环越少越好(2个)
(质数:一个大于1的自然数,除了1和它本身,不能被其他数整除的数字);
# 1.转发
## (1)什么是转发?
一个web组件将未完成的处理交给另外一个web组件继续做。
注:
web组件: jsp或者servlet的统称。
通常是一个servlet获得数据,然后转发给一个jsp
来展现。
![](forward.png)
## (2)如何转发?
step1.绑订数据到request对象上。
request.setAttribute(String name,Object obj);
注:
a. name通常称之为绑订名,obj称之为绑订值。
b. 该方法内部的实现:就是以name作为key,以
obj作为value,调用Map.put方法。
c. Object request.getAttribute(String name);
step2.获得转发器。
RequestDispatcher rd =
request.getRequestDispatcher(Sting uri);
注:
a.uri:转发的目的地,通常是一个jsp。
b.RequestDispatcher是一个接口,该方法会返回 一个符合该接口的对象,这个对象一般我们称 之为转发器。
c.转发的本质是一个web组件通知容器去调用另外一个web组件,可以将转发器理解为web组件通知容器的媒介。
step3.转发
rd.forward(request,response);
## (3)特点
a.转发之后,浏览器地址栏的地址不变。
b.转发的目的地有限制,要求属于同一个web应用。
# 2.比较转发与重定向
## (1)地址栏地址有无变化
转发之后,浏览器地址栏地址不变;重定向之后,浏览器
地址栏地址会发生改变。
## (2)目的地有无限制
转发有限制,重定向没有任何限制。
## (3)能否共享request对象和response对象。
转发可以,重定向不行。
注:
容器收到请求之后,会立即创建request对象和
response对象。当响应发送完毕,容器会立即销毁
这两个对象。也就是说,request对象和response
对象的生存时间是一次请求与响应期间存在。
重定向是两次请求。
## (4)一件事是否完成
转发是一件事未做完,让另外一个web组件继续做;
而重定向是一件事已经完成,再做另外一件独立的事件。
# 2.路径问题
链接、表单提交、重定向和转发如何填写相应的路径
<a href=""></a>
<form action="">
response.sendRedirect("")
request.getRequestDispatcher("")
## (1)什么是相对路径?
不以"/"开头的路径
## (2)什么是绝对路径?
以"/"开头的路径
## (3)如何写绝对路径?
链接、表单提交、重定向从应用名开始写;转发
从应用名之后开始写。
注:
不要将应用名直接写在路径里面!
应该使用以下方法来获得实际部署时的应用名:
String request.getContextPath();
在实际开发时,建议尽量使用绝对路径。
# 练习
添加用户时,如果用户名已经存在,则在添加用户的页面上
提示“用户名已经存在”。否则,将用户信息插入到数据库,然后重定向到用户列表。
## 提示:
step1.在UserDAO类中添加一个方法
public User findByUsername(String uname);
step2.修改AddUserServlet
调用UserDAO的findByUsername方法,如果返回
值不为null,则绑订错误提示信息到request,然后
转发到addUser.jsp;否则调用UserDAO的save方法,
将用户信息插入到数据库。
step3.修改addUser.jsp (显示提示信息)
—————————————————————————————————
# 1. 状态管理
## (1)什么是状态管理?
将浏览器与web服务器之间多次交互当做一个整体来处理,
并且将多次交互所产生的数据(即状态)保存下来。
## (2)如何进行状态管理?
a.方式一 将状态保存在浏览器端
通常使用Cookie技术。
b.方式二 将状态保存在服务器端
通常使用Session技术。
## (3)Cookie
### 1)什么是Cookie?
服务器临时存放在浏览器端的少量数据,
用于跟踪用户的状态。
当浏览器访问服务器时,服务器会将少量数据以
set-cookie消息头的方式发送给浏览器,浏览器
会将这些数据保存下来。
当浏览器再次访问服务器时,会将这些数据以cookie
消息头的方式发送给服务器。
![](cookie.png)
### 2)如何添加Cookie?
Cookie c = new Cookie(String name,String value);
注:
name一般称之为cookie名,value称之为cookie值,都必须是字符串。
response.addCookie(c);
### 3)如何读取Cookie?
Cookie[] request.getCookies();
注:
该方法有可能返回null。
String cookie.getName();
String cookie.getValue();
### 4)cookie的生存时间
a.默认情况下,浏览器会将cookie保存在内存里面,浏览器
只要关闭,cookie会被删除。
b.可以调用setMaxAge方法来设置cookie的生存时间
cookie.setMaxAge(int seconds);
注:
a.单位是秒。
b.当seconds > 0,浏览器会将cookie保存在硬盘上,当超过指定的时间,浏览器会将cookie删除。
c.当seconds < 0,缺省值(浏览器会将cookie保存在内存里面)。
d.当seconds = 0,删除cookie。
比如,要删除一个名称为"username"的cookie,代码如下:
Cookie c = new Cookie("username","");
c.setMaxAge(0);
response.addCookie(c);
### 5)cookie的编码问题
a.什么是cookie的编码问题?
cookie只能存放合法的ascii字符,如果要存放中文,
需要将中文转换成合法的ascii字符的形式。
b.如何处理?
String URLEncoder.encode(String str,String charset);
String URLDecoder.decode(String str,String
charset);
建议,在实际开发时,对添加的数据统一使用encode
方法来编码。
### 6)cookie的路径问题
a.什么是cookie的路径问题?
浏览器访问服务器时,会比较请求地址是否与cookie
的路径匹配,只有匹配的cookie才会被发送。
b.cookie的默认路径
cookie的默认路径等于添加该cookie的web组件的路径,比如AddCookieServlet(/day06/addCookie) 添加了一个cookie,则该cookie的默认路径是
"/day06"。
c.匹配规则
请求地址要么是等于cookie的路径,要么是cookie的
子路径,只有符合该条件的cookie,浏览器才会发送出去。
![](path.png)
d.修改路径
cookie.setPath(String path);
注:
path就是路径。
### 7)cookie的限制
a. cookie可以被用户禁止。
b. cookie不安全。
对于敏感数据,一定要加密。
c. cookie只能保存少量的数据。
大约4k左右
d. cookie的数量也有限制。
大约是几百个
e. cookie只能保存字符串。
# 练习
写一个Servlet,该Servlet先查看有没有一个名称为
"cart"的cookie,如果有,则显示该Cookie的值;如果
没有,则添加之。
# 练习
写一个Servlet,该Servlet先查看有没有一个名称为"Cart"的cookie,如果有,则显示该cookie的值,如果没有则添加。
new Cookie("cart","123");
—————————————————————————————————
# 1.Session(会话)
## (1)session是什么?
服务器端为了保存状态而创建的一个特殊的对象。
注:
当浏览器访问服务器时,服务器端创建一个特殊的
对象(该对象一般称之为session对象,该对象有一个
唯一的id,一般称之为sessionId)。服务器会将sessionId以cookie的方式发送给浏览器。
当浏览器再次访问服务器时,会将sessionId发送
过来,服务器端可以依据sessionId找到对应的session
对象。
## (2)如何获得session对象?
### 1)方式一:
HttpSession s =
request.getSession(boolean flag);
注:
a.HttpSession是一个接口。
b.如果flag为true:
先查看请求当中是否有sessionId,如果没有,
则创建一个session对象;如果有sessionId,
则依据sessionId查找对应的session对象,如果找
到了,则返回该对象,找不到,则创建一个新的
session对象。
c.如果flag为false:
先查看请求当中是否有sessionId,如果没有,
返回null;如果有sessionId,则依据sessionId查找对应的session对象,如果找到了,则返回该对象,找不到,返回null。
![](session.png)
### 方式二:
HttpSession s = request.getSession();
等价于 request.getSession(true);
## (3)常用方法
1)session.setAttribute(String name,Object obj);
注:
以name作为key,以obj作为value,将数据存放到了
一个Map对象里面。
2)Object session.getAttribute(String name);
注:
如果绑订值不存在,返回null。
3)session.removeAttribute(String name);
注:
解除绑订。
![](count.png)
## (4)session超时
a.什么是session超时?
服务器会将空闲时间过长的session对象删除掉。
注:
缺省的超时时间长度一般是30分钟。
b.如何修改超时时间长度?
方式一 修改web.xml配置文件。
<session-config>
<session-timeout>30</session-timeout>
</session-config>
方式二
session.setMaxInactiveInterval(int seconds)
注:
设置两次请求之间的最大间隔时间,如果超过了
该时间,则session对象会被删除。
## (5)删除session
invalidate();
如:
session.invalidate()
## 2. 登录
## 3. session验证
step1.登录成功之后,在session对象上绑订一些数据,
比如:
session.setAttribute("user",user);
step2.当用户访问需要受保护的资源时(即只有登录成功之后才能访问的资源,比如success.jsp),进行session验证,比如:
Object obj = session.getAttribute("user");
if(obj == null){
//没有登录,重定向到登录页面
response.sendRedirect("login.jsp");
return;
}
![](session_check.png)
# 练习
显示用户上一次访问的时间,如果是第一次访问,则输出“你是第一次访问”。
—————————————————————————————————
# 1.比较session与cookie
session相对于cookie、优点是更安全、可以保存更
多的数据、支持更丰富的数据类型。缺点是需要占用服务器
端的内存空间。
# 2.Servlet的生命周期
## (1)什么是servlet的生命周期?
servlet容器如何创建servlet对象、如何对该对象进行初
始化处理、如何调用该对象处理请求,以及如何销毁该对象的
整个过程。
![](life.png)
## (2)分成哪几个阶段?
### 1)实例化
a.什么是实例化?
容器调用servlet构造器,创建servlet对象。
b.什么时候实例化?
情形1: 容器收到请求之后,才会创建。
情形2: 容器启动之后,立即创建。
注: 需要在web.xml文件当中,使用
load-on-startup来配置。
![](s1.png)
c.容器只会创建一个实例!
### 2)初始化
a.什么是初始化?
容器在创建好servlet对象之后,会立即调用该对象的
init(ServletConfig config)方法。
注:
init方法只会调用一次!
b.GenericServlet已经提供了init方法的实现:
将容器传递过来的ServletConfig对象保存下来,并
且提供了一个方法(getServletConfig)来获得该对象。
![](s2.png)
c.如何实现自已的初始化处理逻辑?
只需要override GenericServlet的init()方法。
![](s3.png)
d.初始化参数
![](a1.png)
![](a2.png)
### 3)就绪(调用)
a.什么是就绪?
容器收到请求之后,调用servlet对象的service
方法来处理。
b.HttpServlet已经提供了service方法的实现:
依据请求类型调用对应的doXXX方法。
注:
比如,get请求会调用doGet方法,
post请求会调用doPost方法。
c.开发人员可以override HttpServlet的service方法,
也可以override doXXX方法。
![](service.png)
### 4)销毁
a.什么是销毁?
容器在删除servlet对象之前,会调用该对象的
destroy方法。
该方法只会执行一次!
b. GenericServlet已经提供了destroy方法的实现:
什么都没有做。
开发人员可以override GenericServlet的destroy
方法来实现自已的销毁处理逻辑。
## (3)相关的接口与类
a. Servlet接口
init(ServletConfig config)
service(ServletRequest req,ServletResponse res)
destroy()
b. GenericServlet抽象类
实现了Servlet接口(主要是实现init、destroy方法)。
c. HttpServlet抽象类
继承了GenericServlet,实现了service方法。
# 练习:计算一个人的BMI指数
bmi指数 = 体重(公斤) / 身高(米) / 身高(米);
如果 bmi指数 < 19,体重过轻。
如果 bmi指数 > 25,体重过重。
其它 体重正常。
19,25要使用初始化参数来配置。
<init-param>
<param-name>min</param-name>
<param-value>19</param-value>
</init-param>
—————————————————————————————————
# 1.过滤器
## (1)什么是过滤器?
servlet规范当中定义的一种特殊的组件,用于拦截servlet
容器的调用过程。
注:
容器收到请求之后,会先调用过滤器,再调用
servlet或者其它资源。
![](filter.png)
## (2)如何写一个过滤器?
step1.写一个java类,实现Filter接口。
step2.在doFilter方法里面,实现拦截处理逻辑。
step3.配置过滤器。(web.xml)
## (3)过滤器的优先级
当有多个过滤器满足拦截的要求,则容器依据
<filter-mapping>配置的先后顺序来执行。
## (4)初始化参数
step1.配置初始化参数
<init-param>
<param-name>size</param-name>
<param-value>5</param-value>
</init-param>
step2.调用FilterConfig提供的getInitParameter
方法来读取初始化参数
//读取初始化参数
int size = Integer.parseInt(
config.getInitParameter("size"));
## (5)过滤器的优点(思考)
# 练习
写一个过滤器,检查评论的字数,如果超过
10个字,提示“评论字数过多”。
# 2.容器如何处理请求资源路径
比如,在浏览器地址栏输入http://ip:port/day09-2/abc.html,浏览器会将"/day09-2/abc.html"作为请求资源
路径发送给服务器(容器)。
step1.默认认为访问的是一个servlet,容器会去查找对应的
servlet。
注:
看web.xml文件中<url-pattern>的配置,有没有
对应的servlet。
<url-pattern>有三种配置方式:
第一种:精确匹配
比如
<url-pattern>/abc.html</url-pattern>
第二种:通配符匹配
使用 "*"号匹配任意的零个或者多个字符,比如
<url-pattern>/*</url-pattern>
<url-pattern>/demo/*</url-pattern>
第三种:后缀匹配
使用"*."开头,后接一个后缀,比如
<url-pattern>*.do</url-pattern>
会匹配所有以.do结尾的请求。
step2 如果没有找到对应的servlet,容器会查找对应位置的文件。
# 3.如何让一个servlet处理多种请求?
step1.采用后缀匹配,比如
<servlet-mapping>
<servlet-name>SomeServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
step2.分析请求资源路径,进行相应的处理。
//先获得请求资源路径
String uri = request.getRequestURI();
System.out.println("uri:" + uri);
//为了方便比较,截取请求资源路径的一部分
String path =
uri.substring(uri.lastIndexOf("/"),
uri.lastIndexOf("."));
System.out.println("path:" + path);
if("/login".equals(path)) {
System.out.println("处理登录请求...");
}else if("/list".equals(path)) {
System.out.println(
"处理用户列表请求...");
}
—————————————————————————————————
## (5)过滤器的优点
a.可以在不修改源代码的基础上,为应用添加新的功能。
b.可以将多个组件相同的功能集中写在过滤器里面,方便
代码的维护。
# 1.监听器
## (1)什么是监听器?
servlet规范当中定义的一种特殊的组件,用于监听servlet
容器产生的事件并进行相应的处理。
注:
主要有两大类事件:
a.生命周期相关的事件:
当容器创建了或者销毁了request,session,
servlet上下文时产生的事件。
b.绑订数据相关的事件:
调用了request,session,servlet上下文的
setAttribute和removeAttribute方法时产
生的事件。
## (2)servlet上下文
### 1)什么是servlet上下文?
容器在启动之后,会为每一个web应用创建唯一的一个符合
ServletContext接口要求的对象,该对象会一直存在,除非
应用被卸载或者容器关闭。
注:
该对象有两个特点:
a.唯一性:一个web应用对应一个上下文。
b.持久性:上下文会一直存在,除非应用被卸载或者容器关闭。
### 2)如何获得servlet上下文
GenericServlet,ServletConfig,FilterConfig,
HttpSession都提供了一个方法(getServletContext)来
获得该对象。
### 3)作用1 绑订数据
注:
request,session,servlet上下文都提供了
绑订数据相关的方法,区别如下:
a.绑订的数据,生存的时间不一样:
request < session < servlet上下文。
在满足使用条件的情况下,优先使用生命周期短的。
![](sctx.png)
b.绑订的数据,可访问的范围不一样:
绑订到session对象上的数据,只有与之对应的用户
能够访问到;绑订到servlet上下文上的数据,所有
用户都可以访问。
![](s1.png)
### 4)作用2:读取全局的初始化参数
step1.配置全局的初始化参数
<!-- 配置全局的初始化参数 -->
<context-param>
<param-name>company</param-name>
<param-value>IBM</param-value>
</context-param>
step2.调用servlet上下文的方法来读取
String company =
sctx.getInitParameter("company");
## (3)如何写一个监听器?
step1.写一个java类,依据监听的事件类型选择实现相应的
监听器接口。
注:
比如,要监听session对象的创建和销毁,需要
实现HttpSessionListener接口。
step2.在接口方法当中,实现监听处理逻辑。
step3.配置监听器。(web.xml)
# 统计在线人数
![](count.png)
# 练习
![](lab.png)
# 2.servlet的线程安全问题
## (1)为什么说servlet会有线程安全问题?
a.容器只会创建一个servlet实例。
b.容器收到一个请求,就会启动一个线程,由该线程来处理
对应的请求。
如果有多个线程同时去调用某个servlet实例的方法,就有可能产生线程安全问题,比如,这些线程要修改servlet的某个
属性值。
![](s2.png)
## (2)如何解决?
使用synchronized对有可能产生线程安全问题的代码加锁。
注:
加锁会影响性能。
# 3.servlet小结
## (1)servlet基础
1)什么是servlet?
2)如何写一个servlet?
3)servlet是如何运行的?
4)http协议(了解)
## (2)servlet核心
1)如何读取请求参数值?
2)表单包含有中文参数值,如何处理?
3)servlet输出中文,如何处理?
4)容器如何处理请求资源路径?
5)如何让一个servlet处理多种请求?
6)转发与重定向
a.什么是重定向?
b.如何重定向?
c.重定向的特点?
d.什么是转发?
e.如何转发?
f.转发的特点?
g.比较转发与重定向
7)线程安全问题
8)servlet的生命周期
a.什么是servlet的生命周期?
b.生命周期分成哪几个阶段?
c.容器会创建几个servlet实例?
d.load-on-startup
e.如何实现自已的初始化处理逻辑?
f.初始化方法会执行几次?
g.doGet/doPost方法的作用?
h.相关的接口与类(Servlet,GenericServlet,
HttpServlet)。
i.ServletConfig。
j.初始化参数的配置。
9)路径问题
10)servlet上下文
a.什么是servlet上下文?
b.有什么特点?
c.如何获得servlet上下文?
d.作用
11)将异常抛给容器来处理
## (3)状态管理
1)什么是状态管理?
2)如何进行状态管理?
3)Cookie
a.什么是cookie?
b.如何添加cookie?
c.添加cookie时需要考虑的三个问题:
生存时间
编码问题
路径问题
d.如何读取cookie?
e.cookie有哪些限制?
4)Session
a.什么是session?
b.如何获得session对象?
c.session常用的方法
d.session超时
e.如何删除session?
f.比较session与cookie?
## (4)数据库访问
1)什么是dao?
2)如何写一个dao?
## (5)过滤器与监听器
## (6)典型案例
用户管理
登录(session验证)
—————————————————————————————————
# 1.jsp基础
## (1)什么是jsp?
sun公司制订的一种服务器端的动态页面技术规范。
注:
虽然使用servlet也可以生成动态页面,但是
过于繁琐(需要使用out.print语句),并且不利于页
面的维护(如果修改页面,就需要修改java代码),所以,
sun才推出了jsp规范。
jsp是一个以.jsp为后缀的文件,主要内容是
html和少量的java代码。容器会将jsp转换成一个
servlet然后执行。
## (2)如何写一个jsp文件?
### 1)step1.写一个以.jsp为后缀的文件
### 2)step2.可以添加如下内容:
a.html(css,js): 直接写。
b.java代码:
第一种:java代码片断
<% java代码 %>
第二种: jsp表达式
<%= java表达式 %>
第三种: jsp声明 (a1.jsp)
<%! 声明一个变量或者方法 %>
c.隐含对象:
什么隐含对象?
直接可以使用的对象。
为什么可以使用这些隐含对象?
容器会自动添加获得这些对象的代码。
有哪些隐含对象?
out,request,response
session
application
pageContext: 容器会为每一个jsp实例创建唯一的
一个符合PageContext接口要求的对象,
该对象会一直存在,除非jsp实例被删除。
作用1:绑订数据。(a2.jsp,a3.jsp)
注:绑订到pageContext上的数据,
只有对应的jsp实例能够访问,类似于“钱包”。
![](pagecontext.png)
作用2:提供了一些方法,用于获得其它
所有隐含对象。
config: ServletConfig (a4.jsp)
exception: 获得异常的描述性信息。(a5.jsp,a6.jsp)
注:只有当page指令的isErrorPage
属性值为true时,才能使用。
page (了解) jsp实例本身。
注:jsp实例是jsp对应的servlet对象。
d.指令
什么是指令?
告诉容器将jsp转换成一个servlet时,做一些额外的处理,比如导包。
指令的语法:
<%@ 指令名 属性=值 %>
page指令
import属性:导包。
pageEncoding属性:设置jsp页面的编码。
contentType属性:设置 response.setContentType的内容。
errorPage属性:指定一个异常处理页面。当jsp
运行时发生了异常,容器会调用异常处理页面。
isErrorPage属性:缺省值是false,如果为true, 就可以使用exception隐含对象。
session属性: (a7.jsp)缺省值是true,如果为false,则不能够使用session隐含对象了。
include指令
告诉容器,在将jsp转换成servlet时,将file
属性指定的文件的内容插入到该指令所在的位置。
file属性:指定被包含的文件名。
注:
被包含的jsp并没有真正执行,只是负责提供
内容。所以,被包含的文件也可以是其它类型
的文件,比如html文件。
taglib指令
导入jsp标签。
e.注释 (a8.jsp)
<!-- 注释的内容 -->
注: 如果被注释的内容是java代码,java
代码会执行,但是执行结果并不会在浏览
器端显示出来。
<%-- 注释的内容 --%>
注:如果被注释的内容是java代码,不会执行。
## (3)jsp是如何执行的?
### step1. 容器要将jsp转换成一个servlet。
html(css,js) ----> 在service方法里面,使用
out.write输出。
<% %> ----> 在service方法里面,照搬。
<%= %> ----> 在service方法里面,使用 out.print输出。
<%! %> ----> 添加新的属性或者方法。
# 2.jsp标签和el表达式
## (1)什么是jsp标签?
是sun公司为了替换jsp中的java代码而推出的一种技术,
语法类似于html标签(有开始标记、属性、结束标签、标签体)。
注:
因为在jsp当中写java代码,不利于jsp文件的
维护,比如美工去修改带有java代码的jsp文件就
很不方便,所以sun才推出了jsp标签技术规范。
使用jsp标签,美工修改就很方便,另外,jsp
页面变得简洁,方便代码的复用。
## (2)什么是el表达式?
是一套简单的运算规则,用于给jsp标签的属性赋值。
注: el表达式也可以脱离jsp标签直接使用。
## (3)el表达式的使用
### 1)读取bean的属性
注(了解):
如果一个类,满足如下几个条件,我们就可以称之为是一个javabean。
public class
public 构造器
最好实现Serializable接口
有一些属性及对应的get/set方法
#### 方式一 ${user.username} e1.jsp
注:
a.执行过程:
容器依次从pageContext-->request-->
session-->application中查找绑订名为
"user"的对象(即调用getAttribute方法),
接下来,调用该对象的"getUsername"方法,
然后输出。
b.优点:
el表达式比java代码更简洁。
会将null转换成""输出。
如果依据绑订名找不到对应的对象,
不会发生空指针异常。
c.可以使用pageScope,requestScope,sessionScope,
applicationScope来指定查找范围
#### 方式二 ${user['username']}
注:
a. []里面还可以使用绑订名。
b. []里面还可以使用从零开始的下标,用于
读取数组中指定下标的某个元素的值。
### 2)使用el表达式做一些简单的运算 (e2.jsp)
#### a.算术运算
+,-,*,/,%
注:
+ 只能求和。
#### b.关系运算
>,<,==,!=,>=,<=
#### c.逻辑运算
&&, ||,!
#### d.empty运算
判断集合是否为空或者是否为一个空字符串,如果是,
返回true。
### 3)读取请求参数值 (e3.jsp)
a.${param.username}
等价于request.getParameter("username");
b.${paramValues.interest}
等价于request.getParameterValues("interest");
# 练习 使用el表达式输出某个员工的所有信息。
Employee类(ename,salary,age)
—————————————————————————————————
# 1.jstl
## (1)什么是jstl?
apache开发的一套jsp标签,后来捐献给了sun,sun将其命名为jsp standard taglib,简称为jstl。
## (2)如何使用jstl?
step1.导包。(jstl)
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
step2.使用taglib指令导入jsp标签。
<%@ taglib uri="" prefix=""%>
uri属性:指定jsp标签的命名空间。
注:
命名空间是为了区分同名的元素在元素前添加
的一段说明。为了防止命名空间也冲突,经常使用域名来允当命名空间。
prefix属性:指定命名空间的别名。
## (3)if标签 (if.jsp)
### 1)语法
<c:if test="" var="" scope="">
标签体
</c:if>
### 2)用法
a.当test属性值为true,执行标签体的内容。
b.test属性可以使用el表达式来计算。
c.var属性用来指定绑订名,scope属性指定绑订范围
(可以是 page,request,session,application),
绑订值是test属性值。
## (4)choose标签 (choose.jsp)
### 1)语法
<c:choose>
<c:when test="">
标签体
</c:when>
<c:otherwise>
</c:otherwise>
</c:choose>
### 2)用法
a.when可以出现1次或者多次,相当于一个if语句,当
test属性值为true时,执行标签体的内容。
b.otherwise可以出现0次或者1次,相当于最后那个else(表示例外)。
## (5)forEach标签 (forEach.jsp)
### 1)语法
<c:forEach items="" var="" varStatus="">
</c:forEach>
### 2)用法
a.用来遍历集合或者数组。
b.items属性用来指定要遍历的集合或者数组,可以
使用el表达式来赋值。
c.var属性用来指定绑订名。
注:
绑订范围固定是pageContext。
该标签每次从集合或者数组中取一个元素,然后将
该元素绑订到pageContext上。
d.varStatus属性用来指定绑订名。
注:
绑订范围固定是pageContext。
绑订值是一个特殊的对象,该对象由该标签内部创建,用来获得当前遍历的状态。比如,该对象提供
了如下几个方法:
getIndex(): 获得当前正在被遍历的元素的下标(从0开始)。
getCount():获得当前正在被遍历的元素的序号(从1开始)。
# 2.自定义标签
## step1.写一个java类,继承SimpleTagSupport类。
注:
标签技术有两种,一种是复杂标签技术(old),
一种是简单标签技术(new)。继承SimpleTagSupport类属于简单标签技术。
## step2.override doTag方法
注:
在该方法里面,写处理逻辑。
## step3.在.tld文件里面描述该标签。
注:
该文件要添加到WEB-INF下,
可以参考c.tld文件来写。
## 参考代码
/**
* 标签类的要求:
* 1.继承SimpleTagSupport类。
* 2.override doTag方法,在该方法里写处理逻辑。
* 3.标签有哪些属性,标签类也得有对应的属性,
* 并且属性名要相同,类型要匹配,还得有对应的
* set方法。
*
*/
public class HelloTag
extends SimpleTagSupport{
private String msg;
private int qty;
public HelloTag() {
System.out.println(
"HelloTag的构造器");
}
public void setMsg(String msg) {
System.out.println(
"HelloTag的setMsg方法...");
this.msg = msg;
}
public void setQty(int qty) {
System.out.println(
"HelloTag的setQty方法...");
this.qty = qty;
}
@Override
public void doTag() throws JspException, IOException {
System.out.println(
"HelloTag的doTag方法...");
/*
* 通过继承自SimpleTagSupport类提供的
* 方法来获得pageContext。
* pageContext提供了获得其它所有隐含对象
* 的方法。
*/
PageContext pctx =
(PageContext)getJspContext();
JspWriter out = pctx.getOut();
for(int i = 0; i < qty; i ++){
out.println(msg + "<br/>");
}
}
}
## 参考配置
<tag>
<name>hello</name>
<tag-class>tag.HelloTag</tag-class>
<!--
body-content用来设置标签体的内容。
有三个值。
empty: 该标签没有标签体。
scriptless:该标签有标签体,但是,标签
体里面不能够出现java代码。即不能够
出现<% %> <%= %> <%! %>
JSP:该标签有标签体,并且标签体里面可以出
现java代码。但是,只有复杂标签技术才
支持该值。
-->
<body-content>empty</body-content>
<attribute>
<name>msg</name>
<!--
值为true,表示该属性是必须的。
-->
<required>true</required>
<!--
值为true,表示该属性可以动态
赋值(比如使用el表达式来赋值)
-->
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>qty</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
# 练习
将day09-lab工程中的listUser.jsp的java代码
使用jsp标签和el表达式来代替。
# 练习
开发一个date标签,可以按照指定的日期格式输出当前的
系统日期。
<d:date pattern="yyyy-MM-dd"%>
—————————————————————————————————
# 1.MVC是什么?
是一种软件架构思想、其核心思想是,在设计一个软件的时候,应该将软件划分成模型、视图、控制器这三种不同
类型的模块。其中,模型负责数据处理(业务逻辑),视图负责数据展现(表示逻辑),控制器负责协调模型和视图。
注:
视图将请求发送给控制器,由控制器来选择对应的
模型来处理;模型返回的结果也要给控制器,由控制器选择对应的视图来展现。
# 2.如何使用MVC?
在开发一个web应用时,我们可以使用servlet充当控制器,
使用jsp充当视图,使用java类充当模型。它们的关系如下图
所示:
![](mvc.png)
# 3.MVC的优点?
a.将数据处理与数据展现分开,方便代码的维护。
注:
比如,模型返回的数据,可以使用不同的视图
来展现。又比如,要调用新的模型,不用修改视图。
b.方便测试。
注:
比如,将业务逻辑写在java类里面,可以直接
测试。如果将业务逻辑写在servlet类里面,需要部署
整个应用才能测试。
c.方便分工协作。
# 4.MVC的缺点
使用MVC,会增加代码量,增加软件设计的难度、相应会增加
软件开发的成本。所以,只有有一定规模、并且要求
具有良好的维护性与扩展性的软件,才需要使用MVC。
# 练习
将day12-lab中所有jsp移到WEB-INF下,修改代码,
使之正常运行。
# 5.实现一个MVC框架(SmartMVC)
## (1)目标
实现一个通用的控制器(DispatcherServlet)。
注:
使用SmartMVC来开发一个web应用,只需要
开发模型和视图。
## (2)架构
### 1)主要组件
a. DispatcherServlet (控制器)
接收请求,依据HandlerMapping的配置,调用
处理器来处理。
依据处理器返回的结果(视图名),调用对应的视图
来展现处理结果。
b. HandlerMapping (映射处理器)
负责提供请求路径与处理器的对应关系。
c. Controller (处理器)
负责处理业务逻辑,返回视图名。
### 2)这几个组件的关系。
step1.请求先发送给DispatcherServlet,DispatcherServlet收到请求之后,会依据HandlerMapping的配置,调用对应的处理器来处理。
step2.处理器(Controller)处理请求,返回视图名给
DispatcherServlet。
step3.DispatcherServlet会依据视图名调用对应的视图。
![](smartmvc.png)
java servlet jsp (服务器端编程)
最新推荐文章于 2021-08-18 22:38:41 发布