Servlet
一、Servlet基础
servlet是什么
其实就是一个Java程序,运行在web服务器上,用于接收和响应客户端的http请求.
更多的是配合动态资源来做.当静态资源也需要使用带servlet,只不过是Tomcat里面已经定义好的一个DefaultServlet.
Hello Servlet
1.写一个web工程,要有一个服务器
2.测试运行web工程
1.创建一个类,实现servlet接口
2.配置servlet,用意 : 告诉服务器,我们的引用有这么些个servlet
再webContent/WEB-INF/web.xml里卖弄写下以下内容.
<!-- 向tomcat报告,引用里面有一个servlet,名字叫做HelloServlet,具体的路径是com.firstweb.HelloServelet -->
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.firstweb.HelloServelet</servlet-class>
</servlet>
<!-- 注册servlet的映射,servletName : 找到赏面注册的具体servlet,url-pattern : 在地址栏上的path,一定要以/打头 -->
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
3.在地址栏上输入http://localhost:8080/项目名称
Servlet执行过程
Servlet通用写法
Servlet (接口)
|
|
GenericServlet
|
|
HttpServlet (用于处理http的请求)
1.定义一个类,继承HttpServlet,复写doGet和doPost
Servlet的生命周期
- 生命周期
从创建到销毁的一段时间
- 生命周期方法
从创建到销毁所调用的那些方法
- 主要方法
-
init方法
1.在创建该Servlet的是历史,就执行该方法 2.一个servle只会初始化一次init方法 3.默认情况下,初次访问该servlet才会创建实例
-
service方法
1.只要客户端来了一个请求,那么就执行一次该方法 2.该方法可以被执行多次
-
destory方法
1.servlet销毁的时候,就会执行该方法 ①该项目冲tomcat里里面移出 ②正常关闭tomcat就会执行shutdown.bat
-
doGet和doPost不算生命周期方法,所谓生命周期方法是指,冲对象的创建到销毁一定会执行的方法,但是这两个方法不一定会被执行.
让servlet创建实例的时机提前
1.默认情况下,只有在初次访问servlet的时候,才会执行init方法,有时候我们可能需要在这个方法里执行一些初始化工作,甚至是做一些比较耗时的逻辑.
2.那么这个时候,初次访问,可能会在init方法中逗留较旧的时间,所以需要使初始化的时间提前一点.
3.在配置的时候,使用load-on-start
元素来指定,给定的数字越小,启动的时机就越早,一般不写负数,从2开始即可.
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.firstweb.HelloServelet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
二、ServletConfig
//1.得到servlet配置对象,专门用于在配置servlet的信息
ServletConfig config = getServletConfig();
//获取道德是配置servlet里面的servlet-name的文本内容
String servletName = config.getServeletName();
System.out.println("servletName=" + servletName);
//2.可以获取具体的某一个参数
String address = config.getInitParameter("address");
System.out.println("address=" + address);
//3.获取所有参数的名称
Enumeration<String> names = config.getInitParameterNames();
//遍历所有的参数名称
while(name.hashMoreElements()){
String key = (String) names.nextElement();
String value = config.getInitParameter(key);
System.out.println("key=" + key + " value=" + value);
}
使用他人开发的servlet,如果刚好这个servlet里面需要一个数字或者变量,我们在注册servlet时,需要在web.xml里生命init-params.
三、HttpServletRequest和HttpServletResponse
Servlet配置方式
-
1.全路径匹配
-
以 / 开始 /a /aa/bb
-
localhost:8080/项目名称/aa/bb
-
-
2.路径匹配,前半段匹配
-
以 / 开始,以 * 结束 /a/*
-
*其实时一个配符,匹配任意文字
-
localhost:8080/项目名称/*
-
-
3.以扩展名匹配
- 写法: /*.扩展名 /*.aa /*.bb
四、ServletContext
- Servlet 上下文
每个java虚拟机中的每个web工程只有一个ServletContext对象
ServletContxet的作用
1.可以获取全局变量
2.可以获取web应用中的资源
3.存取数据,servlet间共享数据 域对象
1.可以获取全局变量
- 声明
<context-param>
<param-name>address</param-name>
<param-name>北京</param-name>
</context-param>
- 获取
//强制类型转换
String address = (String)getServletContext().getInitParameter("address");
ServeletContext context = getServletContext();
String address = context.getInitParameter("address");
2.可以获取web应用中的资源
-
获取资源在tomcat里面的绝对路径
- 到的是项目在tomcat里面的根目录
ontext.getRealpath("");
- 这里得到的是文件的绝对路径
String path = context.getRealPath("file/config.properties");
//1.ServletContext对象 ServletContext context = getServletContext(); //获取给定文件在服务器上的绝对路径 String path = context.getRealPath("file/config.properties"); //2创建属性对象 Properties properties = new Properties(); InputStream is = new FileInputStream(path); properties.load(is); //3.获取name属性的值 String naem = properties.getProperty("name");
- 到的是项目在tomcat里面的根目录
-
getResourceAsStream获取资源流对象
- 根据classloader去获取工程下的资源 加载器(JDBC)<
3.存取数据,servlet间共享数据 域对象
-
①定义一个html页面,定义一个form表单
-
login.html <body> <h2>请输入以下内容,完成登录</h2> <form action="LoginServlet" method="get"> 账号: <input type="text" name="username"/><br> 密码: <input type="password" name="password"/><br> <input type="submit" value="登录"/> </form> </body>
- 细节处理
<!-- A路径:Servlet的路径: --> <!-- http:localhost:8080/Demo04/LoginServlet --> <!-- B路径:当前这个html的路径 --> <!-- http:localhost:8080/Demo04/login.html --> <!-- 所以action的值为servlet的路径 --> <form action="LoginServlet" method="get"> <!-- 也可以写绝对路径路径 --> <form action="/Demo04/LoginServlet" method="get">
-
-
②定义一个Servlet,名为LoginServlet
LoginServlet.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取数据
String userName = request.getParameter("username");
String password = request.getParameter("password");
//2.校验数据
}
- ③针对成功或者失败,进行判断,然后跳转新页面
LoginServlet.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取数据
String userName = request.getParameter("username");
String password = request.getParameter("password");
//2.校验数据
//向客户端输出内容
PrintWriter pw = response.getWriter();
if("admin".equals(userName) && "123".equals(password)){
//跳转到成功得界面
//设置状态码 重新定位 状态码
response.setStatus(302);
//定位跳转到得页面
response.setHeader("Location", "login_success.html");
}
else{
pw.write("login failed!");
}
}
- ④统计成功登录次数
if("admin".equals(userName) && "123".equals(password)){
//1.成功的次数累加
//获取以前的数据,在旧值得基础上加1
Object obj = getServletContext().getAttribute("count");
//默认就是0
int totalCount = 0;
if(obj != null) {
totalCount = (int)obj;
}
//累加
getServletContext().setAttribute("count", totalCount + 1);
//2.跳转到成功得界面
}
- ⑤在界面上显示成功登录数量
<body>
<h2>登录成功</h2>
<a href="CountServlet">获取网站登陆成功总数</a>
</body>
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter pw = response.getWriter();
int Count = (int)getServletContext().getAttribute("count");
pw.write("登录人数:" + Count);
}
Servlet何时创建,何时销毁
创建:服务器启动的时候,会为托管得每一个web应用程序创建一个servletContext对象。
销毁:从服务器移除托管,或者是关闭服务器。
- ServletContext 的作用范围
只要在这个项目里面都可以取数据
五、HttpServletRequest
这个对象封装了客户端提交过来的所有数据。
1.获取头信息
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.取出请求里面的所有头信息,得到一个枚举集合
Enumeration<String> headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()) {
String name = (String)headerNames.nextElement();
String value = request.getHeader(name);
System.out.pr intln(name + " = " + value);
}
}
得到的头数据
accept = image/gif, image/jpeg, image/pjpeg, application/x-ms-application, application/xaml+xml, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
accept-language = zh-Hans-CN,zh-Hans;q=0.8,en-US;q=0.5,en;q=0.3
cache-control = no-cache
ua-cpu = AMD64
accept-encoding = gzip, deflate
user-agent = Mozilla/5.0 (Windows NT 6.2; Win64; x64; Trident/7.0; rv:11.0) like Gecko
host = localhost:8080
connection = Keep-Alive
accept = image/gif, image/jpeg, image/pjpeg, application/x-ms-application, application/xaml+xml, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
accept-language = zh-Hans-CN,zh-Hans;q=0.8,en-US;q=0.5,en;q=0.3
cache-control = no-cache
ua-cpu = AMD64
accept-encoding = gzip, deflate
user-agent = Mozilla/5.0 (Windows NT 6.2; Win64; x64; Trident/7.0; rv:11.0) like Gecko
host = localhost:8080
connection = Keep-Alive
2.获取请求体信息
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//2.获取请求体数据,即客户端提交的数据
String name = request.getParameter("name");
String address = request.getParameter("address");
//获取所有参数,得到一个枚举集合
Enumeration<String> parameterNames = request.getParameterNames();
//获取所有参数,得到一个枚举集合,一个key可以对应多个值
Map<String, String[]> parameterMap = request.getParameterMap();
Set<String> keySet = parameterMap.keySet();
Iterator<String> iterator = keySet.iterator();
while(!iterator.hasNext()) {
String key = (String)iterator.next();
String value = parameterMap.get(key)[0]; //对应第一个值
//String value1 = parameterMap.get(key)[1];
}
}
3.获取中文数据
客户端提交给服务器端的数据中如果带有中文,有可能出现乱码情况,可以参照一下的方法解决。
-
如果是GET方式
- 1.编码转换
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String userName = request.getParameter("username"); //GET请求过来的数据,在rul地址栏上就已经经过编码了,所有我们得到的是乱码 //tomcat收到了这批数据,getParameter默认使用ISO-8859-1去解码,XXX.getBytes("ISO-8859-1") //先让文字回到ISO-8859-1对应的字节数组,然后再按utf-8编码 userName = new String(userName.getBytes("ISO-8859-1"),"UTF-8"); }
- 2.直接在tomcat里面做配置(conf/server.xml,加上URIEncoding=“utf-8”),以后get请求的数据就都用utf-8编码
-
如果是POST方法
//doPost调用DoGet方法
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//这个说的是设置请求体里面的文字编码,对get方式无效
request.setCharacterEncoding("UTF-8");
//这行设置一定要写在getParameter之前
String userName = request.getParameter("username");
}
六、HttpServletResponse
负责返回数据给客户端。
1.返回数据
- 输出数据到页面上
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //以字符流的方式写数据 response.getWriter().write("<h1>hello response...</h1>"); //以字节流的方式写数据,注意getBytes() response.getOutputStream().write("<h1>hello response...222</h1>".getBytes()); //设置当前请求的处理状态码 response.setStatus(""); //设置一个头 response.setHeader(name, value); //设置响应的内容类型,以及编码 response.setContentType(type); }
- 响应的数据中有中文,那么可能出现乱码
- 以字符流输出
//这里写出去的文字,默认使用的是ISO-8859-1,我们可指定编码类型 //1.指定输出到客户端的时候,文字使用UTF-8编码 response.setCharacterEncoding("UTF-8"); //2.指定浏览器得到数据时,使用UTF-8解码 response.setHeader("Content-Type", "text.html;charset=UTF-8"); //以字符流的方式写数据 response.getWriter().write("<h1>你好响应</h1>");
- 以字节流输出
//1.指定浏览器得到数据时,使用的码表 response.setHeader("Content-Type", "text.html;charset=UTF-8"); //2.指定输出中文使用的码表,默认为UTF-8 // response.getOutputStream().write("你好,响应".getBytes("UTF-8")); response.getOutputStream().write("你好,响应".getBytes());
- 不管是字节流还是字符流,可直接使用一行代码,然后写数据即可
//设置响应的数据类型是UTF-8,并且告知浏览器使用UTF-8来编码 response.setContentType("text.html;charset=UTF-8");
2.下载文件
- 使用Tomcat的默认servlet去提供下载
index.html 让Tomcat的默认servlet去提供下载<br> <a href="download/aa.jpg">aa.jpg</a><br> <a href="download/bb.txt">bb.txt</a><br> <a href="download/cc.rar">cc.rar</a><br>
- 手动编码提供下载
- index.html
手动编码提供下载<br> <a href="Demo01?filename=aa.jpg">aa.jpg</a><br> <a href="Demo01?filename=bb.txt">bb.txt</a><br> <a href="Demo01?filename=cc.rar">cc.rar</a><br>
- Demo01.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.获取需要下载的文件名字 ----inputStream String fileName = request.getParameter("filename"); //2.获取该文件在tomcat下的绝对路径 //注意download后面的斜杠 String path = getServletContext().getRealPath("download/"+fileName); //3.让浏览器收到资源时,一下在的方式提醒用户,而不是直接展示 response.setHeader("Content-Disposition", "attachment;filename="+fileName); }
- 以流的形式输出
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String fileName = request.getParameter("filename") String path = getServletContext().getRealPath("download/"+fileName); response.setHeader("Content-Disposition", "attachment;filename="+fileName); //转化成输出流 InputStream is = new FileInputStream(path); OutputStream os = response.getOutputStream(); int len = 0; byte[]buffer = new byte[1024]; while((len = is.read(buffer)) != -1) { os.write(buffer,0,len); } os.close(); is.close(); }
3.中文名文件下载
- 手动编码提供下载
<a href="Demo01?filename=张三.txt">张三.txt</a><br>
- 对中文进行编码
- 对得到的文件名进行重新编码
fileName = new String(fileName.getBytes("ISO-8859-1"),"UTF-8");
- 根据浏览器类型编码
/* * 如果是IE、Chrome浏览器,使用URLEncoding编码 * 如果是Firefox,使用Base64编码 */ //获取来访的而客户端类型 String clientType = request.getHeader("User-Agent"); if(clientType.contains("Firefox")) { fileName = DownLoadUtil.base64EncodeFileName(fileName); }else { fileName = URLEncoder.encode(fileName, "UTF-8"); }
- base64编码
- Java如何进行Base64的编码(Encode)与解码(Decode)
- DownLoadUtil类的实现
import java.io.UnsupportedEncodingException; import java.util.Base64; public class DownLoadUtil { public static String base64EncodeFileName(String fileName) { Base64.Encoder base64Encoder = Base64.getEncoder(); try { return "=?UTF-8?B?" + new String(base64Encoder.encode(fileName.getBytes("UTF-8"))) + "?="; }catch(UnsupportedEncodingException e) { e.printStackTrace(); throw new RuntimeException(); } } }
- Java如何进行Base64的编码(Encode)与解码(Decode)
七、重定向和请求转发
重定向
- 代码
//以前的写法
response.setStatus(302);
response.setHeader("Location", "login_success.html");
// 重定向的写法:参数--跳转的位置
response.sendRedirect("login_success.html");
- 特点
- 1.地址上显示的是最后那个资源的路径地址
- 2.请求的次数至少有两次,服务器在一次请求后,会返回一个302以及一个地址,浏览器根据这个地址执行第二次访问。
- 3.可以跳转到任意路径
- 4.效率稍微低一点,执行两次请求。
- 5.后续的请求,没法使用上一次的request存储的数据,或者没法使用上一次的request对象,因为两次的请求不同。
请求转发
- 代码
//请求转发的写法:参数--跳转的位置
request.getRequestDispatcher("login_success.html");
- 特点
- 1.地址栏上显示的是请求servlet的地址
- 2.请求次数只有一次,服务器内部版客户执行了后续的操作
- 3.只能跳转自己项目的资源路路径
- 4.效率稍微搞一单,执行一次请求
- 5.可以使用上一次的request对象