2016-6-4
Servlet
jakarta ee 文档 : https://jakarta.ee/learn/#documentation jakartaee-tutorial: https://jakarta.ee/learn/docs/jakartaee-tutorial/current/index.html
- Java Servlet 3.1: 该版本于2013年发布,引入了一些新特性,包括对非阻塞 I/O 的支持、对 WebSockets 的原生支持以及对 Servlet 容器的配置灵活性的增强。
- Java Servlet 4.0: Servlet 4.0 是 Java EE 8 的一部分,于2017年发布。这个版本引入了对 HTTP/2 的支持、对 Server Push 的支持、对 HTTP Upgrade 的支持以及对新的 HTTP 方法的支持。
- Java Servlet 5.0: Servlet 5.0 是 Jakarta EE 9.1(原名 Java EE)的一部分,于2021年发布。这个版本引入了对 HTTP/3 和 Java 11 的全面支持,以及对 HTTP 头的新功能和增强。
4.0及之前的servlet-api由Oracle官方维护
而5.0及以后的servlet-api由Eclipse开源社区维护
生命周期
https://www.geeksforgeeks.org/life-cycle-of-a-servlet/

- 初始化阶段 当客户端向 Servlet 容器发出 HTTP 请求要求访问 Servlet 时,Servlet 容器首先会解析请求,检查内存中是否已经有了该 Servlet 对象,如果有,则直接使用该 Servlet 对象,如果没有,则创建 Servlet 实例对象,然后通过调用 init() 方法实现 Servlet 的初始化工作。
在 Servlet 的整个生命周期内,它的 init() 方法只调用一次。
- 运行阶段 这是 Servlet 生命周期中最重要的阶段,在这个阶段中,Servlet 容器会为这个请求创建代表 HTTP 请求的 ServletRequest 对象和代表 HTTP 响应的 ServletResponse 对象,然后将它们作为参数传递给 Servlet 的 service() 方法。 service() 方法从 ServletRequest 对象中获得客户请求信息并处理该请求,通过 ServletResponse 对象生成响应结果。
在 Servlet 的整个生命周期内,对于 Servlet 的每一次访问请求,Servlet 容器都会调用一次 Servlet 的 service() 方法,并且创建新的 ServletRequest 和 ServletResponse 对象,也就是说,service() 方法在 Servlet 的整个生命周期中会被调用多次
- 销毁阶段 当服务器关闭或 Web 应用被移除出容器时,Servlet 随着 Web 应用的关闭而销毁。在销毁 Servlet 之前,Servlet 容器会调用 Servlet 的 destroy() 方法,以便让 Servlet 对象释放它所占用的资源。
在 Servlet 的整个生命周期中,destroy() 方法也只调用一次
手搓servlet app
%TOMCAT_HOME%/webapps/xxx下新建自定义名字(xxx)项目文件夹- 引入servlet-api.jar 包
- servlet app 目录说明:
| 目录/文件 | 说明 |
|---|---|
WEB-INF/ | 包含Web应用程序的部署描述符、编译后的类文件和依赖库。 |
WEB-INF/web.xml | Web应用程序的部署描述符,配置Servlet、Filter等组件。 |
WEB-INF/classes/ | 存放编译后的Java类文件。 |
WEB-INF/lib/ | 存放Web应用程序所需的依赖库(JAR文件)。 |
META-INF/ | 可选,包含一些元数据文件。 |
开发一个用户管理Web项目
目录
servlet_1 1.servlet开发流程 生命周期,三种实现方式 2.什么是servlet? 3.Servlet的运行过程 (再谈)
servlet_2 1.同一个用户的页面数据共享 1.1. cookie 1.2. sendRedirect() 跳转 1.3. 隐藏表单 1.4.session 技术
servlet_3 1.servlet 如何操作数据库 2.SQL注入
servlet_4 1.分页算法
servlet_5 1.cookie技术
servlet_6 1.网站框架的改进(MV模型)
servlet_7 1.什么是ServletContext?
servlet_8 功能添加
servlet_9 功能添加
servlet_10 功能添加 <<界面优化>> <<删除用户>> <<修改用户>> <<添加用户>> <<查找用户>>
Tomcat SSL配置{ 1.通过java的keytool工具创建证书 2. servlet配置SSL连接器 … 4.强制某个WEB应用访问https 5.配置tomcat-users
} 后续{ 1.文件上传
}
servlet_1{
<tomcat-users>
<role rolename="manager"/>
<user name="tomcat" password="tomcat" roles="tomcat" />
<user name="role1" password="tomcat" roles="role1" />
<user name="both" password="tomcat" roles="tomcat,role1" />
<user username="admin" password="admin" roles="manager"/>
</tomcat-users>
1.servlet开发流程,生命周期,三种实现方式
1.1 servlet开发流程
1. %TOMCAT_HOME%webapps下新建自定义名字项目文件夹
2. 引入servlet-api.jar 包
3. 部署servlet项目文件夹有WEB-INF;
WEB-INF\classes 存放编译好的servlet ;
WEB-INF\lib 该web app用到的库文件;
WEB-INF\web.xml 该web app的配置文件;
1.2 生命周期:
访问http://localhost:8080/MyWeb/yy ->容器(如:tomcat,Jboss)装载servlet->
调用servlet的init方法(只调用一次初始化)->
调用servlet的service方法处理一般业务逻辑(每次访问都会调用)->
调用servlet的destroy方法销毁( 1.reload 该Servlet(webapps) 2.关闭tomcat 3.关机 该方法会被调用)
tomcat(开源的servlet容器可以受http请求,或者转发到(servlet/jsp);返回静态页面给用户)
servlet(java 服务器小程序(执行java))[如:操作数据库,访问返回给tomcat]
1.3.Servlet 的三种实现方法
1.1 实现Servlet接口
1.2 继承GenericServlt的形式开发
1.3 继承HttpServlet 的形式开发
2.什么是servlet?
引用:
Servlet(Server Applet), 全称Java Servlet; 是用Java编写的服务器端程序;
其主要功能在于交互式地浏览和修改数据, 生成动态Web内容;
【狭义的Servlet是指Java语言实现的一个接口】, 【广义的Servlet是指任何实现了这个Servlet接口的类】,
一般情况下, 人们将Servlet理解为后者;
Servlet运行于支持Java的应用服务器中; 从原理上讲, Servlet可以响应任何类型的请求,
但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器;
servlet就是一个java类, 只不过运行在一个servlet容器中作为请求的后台服务提供者;
3.Servlet的运行过程
Servlet程序是由WEB服务器调用, web服务器收到客户端的Servlet访问请求后:
①Web服务器首先检查是否已经装载并创建了该Servlet的实例对象; 如果是, 则直接执行第④步, 否则, 执行第②步;
②装载并创建该Servlet的一个实例对象;
③调用Servlet实例对象的init()方法;
④创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,
然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去;
⑤WEB应用程序被停止或重新启动之前, Servlet引擎将卸载Servlet, 并在卸载之前调用Servlet的destroy()方法;
}
servlet_2{
1.同一个用户的页面数据共享
1.1. cookie
1.2. sendRedirect() 跳转
1.3. 隐藏表单
1.4.session 技术
1.1. cookie :
参见servlet_5笔记
1.2. sendRedirect() 跳转:
使用sendRedirect()实现不同页面的数据共享
注意:
res.sendRedirect("wel?uname="+u);
1.用[?]号跟url分开,多个数据用[&]符隔开.
2.传送信息比较快,但只能传送字符串不能传送对象.
1.3. 隐藏表单:
"<input type=hidden name=sex value = man>"
跟普通表单差不多,但是用户是看不到的.
1.4.session 技术:
session,用户访问某个网站时,(服务器暂时为该用户独立出一部分内存空间,
作数据共享[其他用户不可访问];默认时间是30min,可以修改)
session作用
防止用户登陆到非法页面
保存登陆信息
...
如何存储?
类似一个两列的表; 一个属性(String)名称对应一个值(object) 理论无限个对应
使用?
1.得到 session:
HttpSession hs = request.getSession(true);//如果没有自动创建一个
2.向session 添加属性:
hs.setAttribute(String name, Object val);//名称,对应的值
3.从session 获得某个属性:
Object val = hs.getAttribute(String name);
4.从session 删除属性:
hs.removeAttribute(String name)//名称
session.invalidate();//清理所有session
session.removeAttrubute(String name);//这里的参数是session变量名称
注意:
session属性默认存在时间是30min,超时会被清除(在30min都没有对该属性进行过操作)
session会为每一个(浏览器)分配一个唯一的session ID[即一个浏览器的软件实例]
session占用服务器内存(注意用户数量多的情况)
}
servlet_3{
1.servlet 如何操作数据库
操作数据库跟java是一样的
serverSQL 2000是: msbase, mssqlserver, msutil
注意:
java连接数据库的三个jar包, mssqlserver.jar, msutil.jar, msbase.jar 需要放到
%TOMCAT_HOME%/commons/lid/下(作用于整个tomcat),或者
%TOMCAT_HOME%webapps/MyWeb**/WEB-INF/lib下(作用于你的webapps)
2.SQL注入
特别注意: SQL注入!
例子 select * from accountTable where userName='abc' and userPassword='abc' or 1 ='1'
or 1 ='1' //即使前面错误,后面条件成立,依然合法!!!
}
servlet_4{
1.分页算法:
定义4个变量
int pageSize; //每页显示多少条记录
int pageNow; //希望显示第几页
int pageCount;//一共有多少页
int rowCount; //一共有多少条记录
pageSize;指定的,pageNow;用户选择,rowCount; 从数据库查到
pageCount;可以计算
if([一共有多少条记录] / 显示多少条记录)
if([一共有多少条记录] % 显示多少条记录 == 0)
{
[一共有多少页] = [一共有多少条记录] / 显示多少条记录
}else{
[一共有多少页] = [一共有多少条记录] / 显示多少条记录 + 1
}
}
servlet_5{
1.cookie技术
cookie 服务端在客户端保存信息(如:登陆用户名,用户密码)
服务端可根据需要读取,写入到客户端
如何存储?
类似一个两列的表; 一个属性(String)名称对应一个值(String)理论无限个对应,注意两个值都是String!
cookie正常是明文保存安全性不高
如何使用?
1. 在服务的创建cookie
Cookie c = new Cookie(String name,String val);
2. 将一个cookie添加(写入)到客户端
response.addCookie(c);
3. 从客户端读取cookie服务端(所有的cookie,以name标识,遍历找不到可能过期)
Cookie[] request.getCookie();//返回值为null 没有Cookie,
4.设置cookie存在时间,不设定时间cookie将不被保存.
c.setMaxAge(int s);//秒 注意不同于session 这个时间是真实的
5. 删除一个cookie,如果是负数不会保存,
Cookie.setMaxAge(0);
cookie 与session
1.cookie 保存在客户端, session 在服务端
2.安全性比较而言 cookie低于session,cookie正常明文保存, 且保存于客户端,所以安全性较低
3.网络传输,cookie通过网络与服务端传输, 而session在服务端不需要传输
4.cookie生命周期累计(以30分钟为例),从创建时开始累计,30分钟后过期, session 生命周期是间隔计时, 在30分钟内
没有访问, or操作才清除, 30分钟内访问过,即从新计时间.
5.关机会影响session,对cookie没有任何影响.
}
servlet_6{
1.网站框架的改进(MV模型)
此前所有的实现 都是将界面ui和业务逻辑处理都放在一起(modell模式),它们有一些问题.
1.logincl, 和 wel 都去操作数据库,它们逻辑相似,代码重复
2.整体没有清晰的层次关系,非常乱
3.代码可读性差,难维护
4.界面改动可能影响业务逻辑
如何改进?
1.分层(界面层,业务逻辑层)[MV模式] ; M(Model 模型) , V(View 视图)
2.将常用(重复性)的代码封装函数.
{
显示层
login,logincl, wel
需要逻辑数据可以到UserBeanCl封装的某个方法访问(必要可以定义,成员字段,或者(UserBean)映射成对象,减少对数据库操作 )
}
{
逻辑层
UserBeanCl (专门操作数据库)
UserBean (数据库一条记录,对应一个UserBean实例,UserBeanCl操作数据库后可以即时分离(关闭数据库链接) )
ConnDB(得到数据库连接)
}
}
servlet_7{
1.什么是ServletContext?
理解ServletContext,要与Cookie,和Session对比,
Cookie和Session无论在客户机还是服务端,都是单个用户数据共享; 而ServletContex存储于服务端
可以被所有客户端访问.
如何存储?
类似一个两列的表; 一个属性(String)名称对应一个值(object) 理论无限个对应
使用?
1. 得到 ServletContext 实例
ServletContext sc = this.getServletContext();
2. 添加属性值
sc.setAttribute(String name, Object val);
3.得到属性值
Object sc.getAttribute(String name);//返回object
4.删除属性值
removeAttribute(String name);
5.生命周期
ServletContext中的属性值的生命周期, 从创建开始 到服务器关闭时结束.( tomcat(容器)关闭 )
注意: ServletContext 好用, 但是ServletContext存储周期相对较长(),非必要不使用.
}
servlet_8{
看项目文件吧=.= }
servlet_9{
看项目文件吧 }
servlet_10{
<<界面优化>>
<<删除用户>>
<<修改用户>>
<<添加用户>>
<<查找用户>>
-------------------------------
<<删除用户>>
集中操作到一个(Main.java)主界面,更好(直观)的多项管理
wel.java(删除用户)->delUsercl.java (独立页面;转发数据库操作到UserBeanCl.java(没有界面,仅作处理后跳转) )=>
UserBeanCl.java(真的操作数据库)---(操作成功)---> Ok.java (成功提示页面)
UserBeanCl.java(真的操作数据库)---(操作失败)--->Err.java (失败提示页面)
--------------------------------------
<<修改用户>>
wel.java(修改用户)->Update.java(独立页面,表单提交.)->Updatecl.java(没有界面,仅作处理后跳转) ->转发操作数据库到UserBeanCl.java=>
UserBeanCl.java(真的操作数据库)---(操作成功)---> Ok.java (成功提示页面)
UserBeanCl.java(真的操作数据库)---(操作失败)--->Err.java (失败提示页面)
-----------------------
<<添加用户>>
main.java(主界面)->AddDate.java(独立页面,表单提交.)->AddDateCl.java(没有界面,调用处理) ->转发操作数据库到UserBeanCl.java=>
UserBeanCl.java(真的操作数据库)---(操作成功)---> Ok.java (成功提示页面)
UserBeanCl.java(真的操作数据库)---(操作失败)--->Err.java (失败提示页面)
-----------------------
<<查找用户>>
main.java(主界面)->FindUsers.java(独立页面,显示结果,转发操作) ->转发操作数据库到UserBeanCl.java->
UserBeanCl.java(真的操作数据库)--<返回结果到>--->>FindUsers.java(显示结果)
}
Tomcat SSL配置{
参考: http://www.cnblogs.com/codewater/articles/2182826.html
1.通过java的keytool工具创建证书
通过java的keytool工具创建证书的命令为:
keytool -genkeypair -alias "yang" -keyalg "RSA"
将生产一对非对称密钥和自我签名的证书, 这个命令中几个参数的意思如下:
-genkeypair: 生成一对非对称密钥;
-alias: 指定密钥对的别名, 该别名是公开的;
-keyalg: 指定加密算法, 本例中的采用通用的RAS加密算法
1.1 首先会提示输入keystore的密码, 这里我输入的密码是sunchis;
1.2 然后提示输入个人信息, 如姓名, 组织单位和所在城市等, 只要输入真实信息即可;
1.3 接着会提示输入信息是否正确, 输入"y"表示信息正确;
以上命令将在操作系统的用户目录下生成名为".keystore"的文件;
1.4 另外, 如果希望生成的keystore文件存放在其他目录中
keytool -genkeypair -alias "yang" -keyalg "RSA" –keystore "D:\sunchis.keystore"
1.5 查看已生成的证书的命令为:
keytool -list -keystore "C:\Documents and Settings\os用户名\.keystore"
2. servlet配置SSL连接器
在Tomcat的server.xml文件中, 已经提供了现成的配置SSL连接器的代码, 只要把<Connector>元素的注释去掉即可:
;(这是Tomcat6 的);
<!-- Define a SSL HTTP/1.1 Connector on port 8443
This connector uses the JSSE configuration, when using APR, the
connector should be using the OpenSSL style configuration
described in the APR documentation -->
<!--
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" keystorePass="*?*"/>
-->
{
在linux下
cd 到java/bin
./keytool -genkey -alias yang -keyalg RSA
//键入必要的信息, 在用户目录下生成.keystore 文件
//查看
keytool -list -keystore /home/yang/.keystore
//server.xml文件,指定证书文件:
keystoreFile="/home/yang/.keystore"
}
实际上, 基于SSL的HTTPS使用的默认端口是443; 但Tomcat在这里将HTTPS端口设置为8443;
<Connector>配置里的一些属性参数如下表:
1.clientAuth : 如果设为true, 表示Tomcat要求所有的SSL客户出示安全证书, 对SSL客户进行身份验证
2.keystoreFile: 指定keystore文件的存放位置, 可以指定绝对路径,
也可以指定相对于<CATALINA_HOME> (Tomcat安装目录)环境变量的相对路径; 如果此项没有设定,
默认情况下, Tomcat将从当前操作系统用户的用户目录下读取名为 ".keystore"的文件;
3.keystorePass: 指定keystore的密码, 如果此项没有设定, 在默认情况下,
Tomcat将使用"changeit"作为默认密码;
4.sslProtocol: 指定套接字(Socket)使用的加密/解密协议,
默认值为TLS, 用户不应该修改这个默认值;
5.ciphers: 指定套接字可用的用于加密的密码清单, 多个密码间以逗号(,)分隔;
如果此项没有设定, 在默认情况下, 套接字可以使用任意一个可用的密码;
3.测试
以https的方式访问;
https://192.168.3.10/
当然这是一个自签证书, 会受到浏览器警告
4.强制某个WEB应用访问https
只需要修改webapps文件夹下各自的web.xml文件(注意: 这是wbapp下的web.xml; 非tomcat的conf/web.xml)
在welcome-file-list元素下增加, 如下:
;
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<login-config>
<!-- Authorization setting for SSL -->
<auth-method>CLIENT-CERT</auth-method>
<realm-name>Client Cert Users-only Area</realm-name>
</login-config>
<security-constraint>
<!-- Authorization setting for SSL -->
<web-resource-collection >
<web-resource-name >SSL</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
; ; ; ; ; ; */
redirectPort="8443"
5.配置tomcat-users
<role rolename="manager-gui"/>
}
文件上传
需要导入jar包 commons-fileupload-1.3.2.jar commons-io-2.5.jar
<form action="upload" method="post" enctype="multipart/form-data">
<input name="f" type="file" />
<input name="feil" value="val" >
<input type="submit" value="提交">
</form> 2.servlet代码
private String filePath="e:/"; // 文件存放目录
private String tempPath="e:/"; // 临时文件目录
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
// Auto-generated method stub
res.setContentType("text/plain;charset=utf-8");
PrintWriter pw = res.getWriter();
try{
DiskFileItemFactory diskFactory = new DiskFileItemFactory();
// threshold 极限, 临界值, 即硬盘缓存 1M
diskFactory.setSizeThreshold(4 * 1024);
// repository 贮藏室, 即临时文件目录
diskFactory.setRepository(new File(tempPath));
ServletFileUpload upload = new ServletFileUpload(diskFactory);
// 设置允许上传的最大文件大小 4M
upload.setSizeMax(4 * 1024 * 1024);
// 解析HTTP请求消息头
List fileItems = upload.parseRequest((HttpServletRequest) req);
Iterator iter = fileItems.iterator();
while(iter.hasNext())
{
FileItem item = (FileItem)iter.next();
if(item.isFormField())
{
System.out.println("处理表单内容 ...");
processFormField(item, pw);
}else{
System.out.println("处理上传的文件 ...");
processUploadFile(item, pw);
}
}// end while()
pw.close();
}catch(Exception e){
System.out.println("使用 fileupload 包时发生异常 ...");
e.printStackTrace();
}// end try ... catch ...
//返回
//res.sendRedirect("/ok.jsp");
}
// // 处理表单内容
private void processFormField(FileItem item, PrintWriter pw)
throws Exception
{
String name = item.getFieldName();
String value = item.getString();
pw.println(name + ": " + value + "\r\n");
}
// 处理上传的文件
private void processUploadFile(FileItem item, PrintWriter pw)
throws Exception
{
// 此时的文件名包含了完整的路径, 得注意加工一下
String filename = item.getName();
System.out.println("完整的文件名: " + filename);
int index = filename.lastIndexOf("\\");
filename = filename.substring(index + 1, filename.length());
long fileSize = item.getSize();
if("".equals(filename) && fileSize == 0)
{
System.out.println("文件名为空 ...");
return;
}
File uploadFile = new File(filePath + "/" + filename);
item.write(uploadFile);
pw.println(filename + " 文件保存完毕 ...");
pw.println("文件大小为: " + fileSize + "\r\n");
}
}