文章目录
6.servlet
6.1.简介
- Servlet是Sun公司开发动态web的一门技术
- Sun公司在这些api中提供了一个接口叫: Servlet , 开发一个servlet程序, 只需两个步骤
- 编写一个类, 实现servlet接口
- 把开发好的java类部署到web服务器中
把实现了Servlet接口的java程序叫做: Servlet
6.2.HelloServlet
Servlet接口Sun公司有两个默认的实现类
- HttpServlet
- GenericServlet
1, 构建一个普通Maven项目
删除src文件
添加一个module,main目录下添加java , resource
修改子项目web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="true">
</web-app>
2,maven父子工程的理解
在父项目中的pom.xml添加了
<modules>
<module>servlet-01</module>
</modules>
在子项目中pom添加了
<parent>
<artifactId>web-02-servlet</artifactId>
<groupId>com.ccc</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
父项目中的java子项目可以直接使用
遇到的问题:
创建maven项目-使用web模板不自动添加parent标签
我这里手动添加的, 或者创建的时候不选模板,手动添加web
3,编写一个Servlet程序
1编写一个普通类, 实现Servlet接口 , 继承HTTPServlet
2重写doPost, doGet方法
package com.ccc.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//ServletOutputStream outputStream = resp.getOutputStream();
PrintWriter writer = resp.getWriter(); //响应流
writer.println("Hello, Servlet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
3编写servlet的映射
- 为什么需要映射: 我们写的是java程序, 要通过浏览器访问, 而浏览器需要连接web服务器, 所以我们需要在web服务中注册我们写的servlet, 还需一个浏览器能访问的地址
<!--注册servlet-->
<!---->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.ccc.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
4, 添加Tomcat
5,启动成功 , 请求hello
6.3.Servlet原理
6.4.Servlet-Mapping
-
1一个Servlet可以指定一个映射路径
-
<!--servlet请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
-
-
2一个servlet可以指定多个映射路径
-
<!--servlet请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello1</url-pattern> </servlet-mapping>
-
-
3一个servlet可以指定通用映射路径
-
<!--servlet请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello/*</url-pattern> </servlet-mapping>
-
-
4默认请求路径
-
<!--servlet请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <!--尽量避免这么写, 会直接访问到servlet, 不走index--> <url-pattern>/*</url-pattern> </servlet-mapping>
-
-
5指定后缀或前缀等等
-
<!--自定义后缀注意: * 前面不能加路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <!--不管前面输入什么, 只要后面是.abcd就走hello--> <url-pattern>*.abcd</url-pattern> </servlet-mapping>
-
6.5.Servlet-Mapping优先级
指定了固有的映射路径优先级最高, 找不到走默认请求
默认走error
hello走hello
其他走error
6.6.ServletContext
web容器启动时, 会为每个web程序创建一个对应的ServletContext对象, 代表了当前的web应用
应用:
1,共享数据
在Servlet1中保存数据, 在servlet2中读取
Servlet1中保存
package com.ddd.servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = "张三";
//获取ServletContext
ServletContext context = this.getServletContext();
//放入数据
context.setAttribute("name",name);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
Servlet2中读取
package com.ddd.servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class GetContextServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*获取ServletContext*/
ServletContext context = this.getServletContext();
//取值
String name = (String) context.getAttribute("name");
//输出到页面
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
resp.getWriter().println("获取到了: "+name);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.ddd.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>getc</servlet-name>
<servlet-class>com.ddd.servlet.GetContextServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getc</servlet-name>
<url-pattern>/getc</url-pattern>
</servlet-mapping>
</web-app>
访问测试
注意: 想要获取到servlet1中保存的数据, 需先进去1 set进去, 2中才能读取到
直接进入2 无法读取
先进入1中放入
在读取
2,获取初始化参数
<!--配置web初始化参数-->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/database</param-value>
</context-param>
通过servletcontext获取
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*获取ServletContext*/
ServletContext context = this.getServletContext();
/*获取参数 */
String url = context.getInitParameter("url");
resp.getWriter().println(url);
}
3,请求转发
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*获取ServletContext*/
ServletContext context = this.getServletContext();
//请求转发到/gp
context.getRequestDispatcher("/getp").forward(req,resp);
}
<servlet>
<servlet-name>dm4</servlet-name>
<servlet-class>com.ddd.servlet.ServletDemo04</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dm4</servlet-name>
<url-pattern>/dm4</url-pattern>
</servlet-mapping>
- 转发请求路径不变
4,读取资源文件
Properties
- 在java目录下新建properties
- 在resource目录下新建properties
/WEB-INF/classes/db.properties
username=zs
password=123321
发现: 都被打包到了同一个目录下:classes , 俗称classpath
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*获取ServletContext*/
ServletContext context = this.getServletContext();
/*把资源转成流*/
InputStream is = context.getResourceAsStream("/WEB-INF/classes/db.properties");
Properties properties = new Properties();
properties.load(is);
String uname = properties.getProperty("username");
String pwd = properties.getProperty("password");
resp.getWriter().println(uname+"::"+pwd);
}
测试读取
6.7.HTTPServletResponse
web服务器接收到客户端http请求时, 针对这个请求, 分别创建了一个代表请求的HttpServletRequest对象, 一个代表响应的HttpServletResponse对象
1,简单分类
**负责向浏览器发送数据的方法: **
public ServletOutputStream getOutputStream() throws IOException;
public PrintWriter getWriter() throws IOException; //中文常用
负责向浏览器发送响应头的方法
public void setCharacterEncoding(String charset);
public void setContentLength(int len);
public void setContentLengthLong(long len);
public void setContentType(String type);
public void setHeader(String name, String value);
响应状态码
/**
* Status code (200) indicating the request succeeded normally.
*/
public static final int SC_OK = 200;
/**
* Status code (300) indicating that the requested resource
* corresponds to any one of a set of representations, each with
* its own specific location.
*/
public static final int SC_MULTIPLE_CHOICES = 300;
/**
* Status code (404) indicating that the requested resource is not
* available.
*/
public static final int SC_NOT_FOUND = 404;
/**
* Status code (500) indicating an error inside the HTTP server
* which prevented it from fulfilling the request.
*/
public static final int SC_INTERNAL_SERVER_ERROR = 500;
/**
* Status code (502) indicating that the HTTP server received an
* invalid response from a server it consulted when acting as a
* proxy or gateway.
*/
public static final int SC_BAD_GATEWAY = 502;
2,常见应用
- 输出信息
- 下载文件
- 要获取下载文件的路径
- 下载的文件名
- 设置浏览器下载参数
- 获取下载文件的输入流
- 创建缓冲区
- 获取outputstream对象
- 将fileoutputstream写入到buffer缓冲区, 将缓冲区内容输出到客户端
package com.eee.servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Enumeration;
public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1. 要获取下载文件的路径
String realPath = "E:\\dx\\xx\\java\\code\\web-02-servlet\\response\\src\\main\\resources\\Servlet大致原理.png";
//2. 下载的文件名
String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
//3. 设置浏览器下载参数
resp.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"UTF-8"));
//4. 获取下载文件的输入流
FileInputStream in = new FileInputStream(realPath);
//5. 创建缓冲区
int len = 0;
byte[] buffer = new byte[1024];
//6. 获取outputstream对象
ServletOutputStream out = resp.getOutputStream();
//7. 将fileoutputstream写入到buffer缓冲区, 将缓冲区内容输出到客户端
while ((len = in.read(buffer))>0){
out.write(buffer,0,len);
}
out.close();
in.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
6.8.HttpServletRequest
HttpServletRequest代表客户端的请求, 用户通过http协议访问服务器, http请求中的所有信息会被封装到HttpServletRequest中, 通过这个对象的方法, 可以获得客户端的所有信息
1, 获取前段传递的参数,请求转发
package com.rrr.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//处理乱码
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
//获取表单数据
String username = req.getParameter("username");
String pwd = req.getParameter("password");
String[] hobbies = req.getParameterValues("hobby");
System.out.println(username+"--"+pwd);
System.out.println(Arrays.toString(hobbies));
//请求转发 /代表当前web应用, 不需要加项目名称
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
2,重定向和转发的区别
URL地址栏 状态码
- 转发: 地址不会变 307 转发地址只需写项目下面的地址
- 重定向: 地址栏会变化 302 重定向地址需写全地址
request传参
- 转发: 页面能接收
- 重定向: 页面接收不到