文章目录
Servlet
1、Servlet简介
- Servlet (Service Applet) 是在服务器上运行的小程序。
- 广义的Servlet是指任何实现了这个Servlet接口的类,Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
2、HelloServlet
- Java提供了两个默认的Servlet接口实现类:
- HttpServlet
- GenericServlet
-
构建一个普通的Maven项目,删掉里面的src目录,以后我们的学习就在这个项目里面建立Moudel,这个空的工程就是Maven主工程
-
Maven父子工程
父项目中会有
<modules> <module>servlet-01</module> </modules>
子项目会有
<parent> <artifactId>javaweb</artifactId> <groupId>com.study</groupId> <version>1.0-SNAPSHOT</version> </parent>
-
-
Maven环境优化
-
修改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>
-
将maven的结构搭建完整
创建 java和 resources 文件夹
-
-
编写一个Servlet程序
-
定义一个类,实现Servlet接口,这里我们直接继承HttpServlet
public class HelloServlet extends HttpServlet { //由于get和post只是请求的不同的方式,所以doGet和doPost业务逻辑都一样,可以相互调用 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); //响应流 writer.print("Hello Servlet"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
-
编写Servlet的映射
<!--注册Servlet--> <servlet> <servlet-name>hello</servlet-name> <servlet-class>com.study.servlet.HelloServlet</servlet-class> </servlet> <!--Servlet的请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
-
配置Tomcat服务器
-
启动发布
3、Servlet原理
4、Mapping配置
- 一个Servlet可以指定一个映射路径
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
- 一个Servlet可以指定多个映射路径
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello3</url-pattern>
</servlet-mapping>
- 一个Servlet可以指定通配的映射路径
<servlet-mapping>
<servlet-name>hello</servlet-name>
<!-- * 通配任意字符串-->
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
- 默认请求路径
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
- 指定后缀或前缀等
<!--
注意点,*前面不能加项目映射的路径
-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>*.study</url-pattern>
</servlet-mapping>
- 优先级问题:指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求
5、ServletContext
web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用。
5.1、共享数据
- 即在一个Servlet中保存的数据,可以在另外一个servlet中拿到
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String username = "张三"; //数据
//将一个数据保存在了ServletContext中,字段名:username 值 “张三”
context.setAttribute("username",username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 获取保存在ServletContext中的数据
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String username = (String) context.getAttribute("username");
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
resp.getWriter().print("名字:"+username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- web.xml配置
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.study.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.study.servlet.GetServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getc</servlet-name>
<url-pattern>/getc</url-pattern>
</servlet-mapping>
-
测试访问
-
若直接访问 http://localhost:8080/s2/getc ,由于username还未赋值,所以username=null;
-
先访问 http://localhost:8080/s2/hello ,将数据存进ServletContext
-
再访问 http://localhost:8080/s2/getc
-
5.2、获取初始化参数
<!--配置一些web应用初始化参数-->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/mydb</param-value>
</context-param>
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String url = context.getInitParameter("url");
resp.getWriter().print(url);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 测试访问:
5.3、请求转发
public class ForwardServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
// "/url" 5.2中的Servlet
context.getRequestDispatcher("/url").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 测试访问:
- 转发过程:
5.4、读取资源文件
-
在java目录下新建properties文件
-
在resources目录下新建properties文件
-
发现:都被打包到了同一个路径下:classes/ ,我们俗称这个路径为classpath
-
maven由于他的约定大于配置,可能出现配置文件无法被导出或者生效的问题,解决方案:
<!--在build中配置resources,来防止我们资源导出失败的问题-->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
- prop.properties
username=root
password=123456
- PropServlet.java
public class PropServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = getServletContext();
InputStream resourceAsStream = context.getResourceAsStream("WEB-INF/classes/prop.properties");
Properties properties = new Properties();
properties.load(resourceAsStream);
String username = properties.getProperty("username");
String password = properties.getProperty("password");
resp.getWriter().print("<h1>"+username+"==="+password+"</h1>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 测试访问:
6、Response
6.1、浏览器下载文件
public class FileDownloadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//需要下载的文件在服务器的路径
String filePath="D:\\IdeaProjects\\maven-javaweb-01\\Servlet-03\\src\\main\\resources\\背景.png";
//文件名
String fileName=filePath.substring(filePath.lastIndexOf('\\')+1);
//设置使浏览器能够支持下载(Content-Disposition)我们需要的东西,中文文件名需要设置编码(URLEncoder.encode),否则有可能乱码
resp.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"UTF-8"));
//创建读取文件的输入流
FileInputStream in = new FileInputStream(filePath);
//获取输出流
ServletOutputStream out =resp.getOutputStream();
//创建buffer缓冲区
byte[] buffer = new byte[1024 * 8];
int len=0;
//将FileOutputStream流写入到buffer缓冲区,使用OutputStream将缓冲区中的数据输出到浏览器!
while ((len=in.read(buffer))!=-1){
out.write(buffer,0,len);
}
in.close();
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 测试访问:
6.2、创建一张图片,在其中生成8位随机数,并响应给浏览器
public class ImageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//让浏览器3秒自动刷新一次
resp.setHeader("refresh","3");
//在内存中创建一个图片
BufferedImage image = new BufferedImage(200, 40, BufferedImage.TYPE_INT_RGB);
//获取图片
Graphics2D g = (Graphics2D) image.getGraphics();
//设置图片背景颜色
g.setColor(Color.cyan);
g.fillRect(0,0,200,40);
//在图片中写入数据
g.setColor(Color.RED);
g.setFont(new Font("华文彩云",Font.BOLD,30));
g.drawString(getNum(),20,30);
//把图片写到浏览器
ImageIO.write(image,"png",resp.getOutputStream());
}
private String getNum() {
Random random = new Random();
StringBuilder sb = new StringBuilder(random.nextInt(99999999));
int sbLen=sb.length();
for (int i = 0; i < 8-sbLen; i++) {
sb.append(random.nextInt(10));
}
return sb.toString();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 测试访问:
6.3、重定向
- RedirectServlet.java
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//重定向
resp.sendRedirect("/s3/success.jsp");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>success</title>
</head>
<body>
<h1>redirect success!</h1>
</body>
</html>
-
测试访问:
-
重定向示意图:
-
重定向和转发的区别:
-
重定向是两次请求,转发是一次请求,因此转发的速度要快于重定向;
-
重定向之后地址栏上的地址会发生变化,变化成第二次请求的地址,转发之后地址栏上的地址不变,还是第一次请求的地址;
-
转发是服务器行为,重定向是客户端行为;
-
重定向时的网址可以是任何网址,转发的网址必须是本站点的网址。
-