文章目录
关注微信公众号"自定义的Vae" 下载笔记
Servlet简介
Servlet是什么?
Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求
和 HTTP 服务器上的数据库或应用程序之间的中间层。
使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。
Java Servlet 通常情况下与使用 CGI(Common Gateway Interface,公共网关接口)实现的程序可以达到异曲同
工的效果。
Servlet 架构
下图显示了 Servlet 在 Web 应用程序中的位置。
HelloServlet
Servlet接口在Sun公司有两个实现类
-
构件一个普通的Maven项目,删掉里面的src目录,以后在这个项目里面建立Moudle,这个空的工程就是Maven主工程
并在pom.xml文件里添加Servlet依赖
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency>
-
在主工程里面建立一个子工程,并勾选webapp
点击next
完成后父项目中pom.xml文件会多一个moudle
去子模块里面pom文件添加parent标签,这样可以继承需要的依赖
-
Maven环境优化
将maven的结构搭建完整
-
编写一个Servlet程序
先创建一个普通的类HelloServlet,然后继承HttpServlet
package com.hs_vae; 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 { System.out.println("进入了doGet方法"); PrintWriter writer = resp.getWriter(); //响应流 writer.print("Hello Servlet"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
-
缩写Servlet的映射
由于我们写的是Java程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务中注册我们写的Servlet,还需要给它一个浏览器能够访问的路径
在web.xml中
<web-app> <display-name>Archetype Created Web Application</display-name> <!-- 注册servlet--> <servlet> <servlet-name>hello</servlet-name> <servlet-class>com.hs_vae.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> </web-app>
-
配置Tomcat服务器(路径写上s1)
-
启动Tomcat服务器
自动打开localhost:8080/s1网页,在后面输入hello,显示Hello Servlet,控制台也显示了信息
Servlet原理
Mapping问题
一个Servlet请求可以指定一个映射路径
<!-- Servlet的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
一个Servlet请求可以指定多个映射路径
浏览器上输入hello1,hello2,hello3都会出现 “Hello Servlet”
<!-- 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请求可以指定通用映射路径
设置在hello路径下任意的映射路径,相当于 localhost:8080/s1/hello/*
<!-- Servlet的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
指定默认请求路径
设置在默认路径下(s1)任意的映射路径 ,相当于 localhost:8080/s1/*,不会进入首页index
<!-- Servlet的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
一个Servlet请求可以指定一个映射路径
<!-- Servlet的请求路径-->
<!-- 注意: *. 前面不能加项目映射路径 比如 /hello/*.hs-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>*.hs</url-pattern>
</servlet-mapping>
修改404页面
第一步,在项目里面建立一个实现类
public class ErrorServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8"); //编码utf-8
resp.setContentType("text/html"); //以html页面展示404页面
PrintWriter writer = resp.getWriter();
writer.print("没有找到资源");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
第二步,在web.xml文件里写上
<servlet>
<servlet-name>error</servlet-name>
<servlet-class>com.hs_vae.ErrorServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>error</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
第三步,启动Tomcat,默认路径s1下任意映射路径都会执行error的servlet
注意这里面存在优先级问题
指定的固有的映射路径优先级最高,如果没有该映射路径就会执行默认的处理请求
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.hs_vae.HelloServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>error</servlet-name>
<servlet-class>com.hs_vae.ErrorServlet</servlet-class>
</servlet>
<!-- Servlet的请求路径-->
<!-- 注意: *. 前面不能加项目映射路径 比如 /hello/*.hs-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<!-- 404页面-->
<servlet-mapping>
<servlet-name>error</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
ServletContext对象
Web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前所有的web应用,处理上下文
ServletContext应用
1、数据共享
比如在Servlet1中保存的数据,可以在另一个Servlet2中得到
第一步,先创建放置数据的类
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
//定义一个数据
String username="胡帅";
//将数据保存在ServletContext中
context.setAttribute("用户名",username);
}
}
第二步,创建读取数据的类
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
//获取ServletContext中的共享数据
String username = (String) context.getAttribute("用户名");
//设置html展示和编码
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>
<servlet-name>hello</servlet-name>
<servlet-class>com.hs_vae.HelloServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>getName</servlet-name>
<servlet-class>com.hs_vae.GetServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>getName</servlet-name>
<url-pattern>/get</url-pattern>
</servlet-mapping>
第四步,测试访问结果
先访问hello映射路径,再访问get映射路径
2、获取初始化参数
第一步,在web.xml文件里面写上参数
<context-param>
<param-name>jdbcURL</param-name>
<param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>
第二步,创建一个获取初始化参数的类
public class Demo03GetParam extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
//获取初始化参数:jdbc的URL
String jdbcURL = context.getInitParameter("jdbcURL");
//打印到页面上
resp.getWriter().print(jdbcURL);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
第三步,在web.xml里注册该类的Servlet
<servlet>
<servlet-name>getParam</servlet-name>
<servlet-class>com.hs_vae.Demo03GetParam</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getParam</servlet-name>
<url-pattern>/getP</url-pattern>
</servlet-mapping>
第四步,启动Tomcat测试
3、请求转发
可以转发一个请求路径,下面举例转发/getP路径下的内容
创建一个转发的类
public class Demo04Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
//转发请求路径,调用forward方法请求转发
context.getRequestDispatcher("/getP").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
在web.xml 文件里添加servlet
<servlet>
<servlet-name>forward</servlet-name>
<servlet-class>com.hs_vae.Demo04Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>forward</servlet-name>
<url-pattern>/forward</url-pattern>
</servlet-mapping>
启动Tomcat,输入映射路径/forward
转发了/getP里面的内容
4、读取资源文件
配置文件properties
- 在java目录下新建properties文件
- 在resource目录下新建properties文件
注意:由于Maven约定大于配置,java目录下的资源文件可能导不出来
要在项目的pom.xml中的build标签补充以下内容,最后这两个目录下的文件都被打包到同一个路径下:classes,这个称为classpath
<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>false</filtering>
</resource>
</resources>
配置好了以后
第一步,先在java目录下建立里建立一个mysql.properties,里面写上username和passowrd
第二步,建立一个读取资源文件的类
public class Demo05Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
//通过文件生成的路径,读取资源文件并转化成流
InputStream is = context.getResourceAsStream("/WEB-INF/classes/com/hs_vae/mysql.properties");
Properties prop = new Properties();
//加载这个流
prop.load(is);
//通过流中的key获得value值
String user = prop.getProperty("username");
String pwd = prop.getProperty("password");
//打印到页面上
resp.getWriter().print(user+":"+pwd);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
第三步,在web.xml里注册servlet
<servlet>
<servlet-name>prop</servlet-name>
<servlet-class>com.hs_vae.Demo05Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>prop</servlet-name>
<url-pattern>/prop</url-pattern>
</servlet-mapping>
第四步,启动Tomcat,网址后面输入/prop
读取配置文件mysql.properties成功
HttpServletResponse
1、简单分类
负责向浏览器发送数据的方法
ServletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() throws IOException;
负责向浏览器发送响应头的方法
void setCharacterEncoding(String var1);
void setContentLength(int var1);
void setContentLengthLong(long var1);
void setContentType(String var1);
void sendError(int var1, String var2) throws IOException;
void sendError(int var1) throws IOException;
void sendRedirect(String var1) throws IOException;
void setDateHeader(String var1, long var2);
void addDateHeader(String var1, long var2);
void setHeader(String var1, String var2);
void addHeader(String var1, String var2);
void setIntHeader(String var1, int var2);
void addIntHeader(String var1, int var2);
响应的状态码
int SC_CONTINUE = 100;
int SC_SWITCHING_PROTOCOLS = 101;
int SC_OK = 200;
int SC_CREATED = 201;
int SC_ACCEPTED = 202;
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
int SC_NO_CONTENT = 204;
int SC_RESET_CONTENT = 205;
int SC_PARTIAL_CONTENT = 206;
int SC_MULTIPLE_CHOICES = 300;
int SC_MOVED_PERMANENTLY = 301;
int SC_MOVED_TEMPORARILY = 302;
int SC_FOUND = 302;
int SC_SEE_OTHER = 303;
int SC_NOT_MODIFIED = 304;
int SC_USE_PROXY = 305;
int SC_TEMPORARY_REDIRECT = 307;
int SC_BAD_REQUEST = 400;
int SC_UNAUTHORIZED = 401;
int SC_PAYMENT_REQUIRED = 402;
int SC_FORBIDDEN = 403;
int SC_NOT_FOUND = 404;
int SC_METHOD_NOT_ALLOWED = 405;
int SC_NOT_ACCEPTABLE = 406;
int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
int SC_REQUEST_TIMEOUT = 408;
int SC_CONFLICT = 409;
int SC_GONE = 410;
int SC_LENGTH_REQUIRED = 411;
int SC_PRECONDITION_FAILED = 412;
int SC_REQUEST_ENTITY_TOO_LARGE = 413;
int SC_REQUEST_URI_TOO_LONG = 414;
int SC_UNSUPPORTED_MEDIA_TYPE = 415;
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
int SC_EXPECTATION_FAILED = 417;
int SC_INTERNAL_SERVER_ERROR = 500;
int SC_NOT_IMPLEMENTED = 501;
int SC_BAD_GATEWAY = 502;
int SC_SERVICE_UNAVAILABLE = 503;
int SC_GATEWAY_TIMEOUT = 504;
int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
2、下载文件
分析步骤:
- 获取需要下载的本地文件路径
- 获取下载的文件名
- 让浏览器能够支持下载,并且将存在的中文进行转码
- 获取下载的文件输入流FileInputStream
- 创建缓冲区
- 获取OutputStream对象
- 将OutputStream对象写入到缓冲区
- 将缓冲区数据输出到客户端
- 关闭流资源
实现类
public class Demo01FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取下载本地的文件路径
String pathname="/home/hs/IdeaProjects/javaWeb_Servlet/response/target/response/WEB-INF/classes/小狗.jpg";
//2.获取下载的文件名
String fileName = pathname.substring(pathname.lastIndexOf("/") + 1);
//3.让浏览器能够支持下载,并将存在的中文名称进行转码
resp.setHeader("Content-Disposition","attachment;filename="+URLEncoder.encode(fileName,"utf-8"));
//4.获取下载文件的输入流
FileInputStream fis = new FileInputStream(pathname);
//5.创建缓冲区
int len=0;
byte[] bytes= new byte[1024];
//6.获取OutputStream对象
ServletOutputStream outputStream = resp.getOutputStream();
//7.将OutputStream对象写入到缓冲区,并使用该对象将缓冲区的数据输出到客户端
while ((len= fis.read(bytes))!=-1){
outputStream.write(bytes,0,len);
}
//8.释放流的资源
fis.close();
outputStream.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
web.xml 注册servlet
<servlet>
<servlet-name>down</servlet-name>
<servlet-class>com.hs_vae.Demo01FileServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>down</servlet-name>
<url-pattern>/down</url-pattern>
</servlet-mapping>
启动Tomcat,网址后面输入/down,下载该图片文件
3、验证码功能
public class Demo02ImageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//让浏览器3秒自动刷新一次
resp.setHeader("refresh","3");
//在内存中创建一个图片
BufferedImage image = new BufferedImage(80,20,BufferedImage.TYPE_INT_RGB);
//得到图片
Graphics2D g = (Graphics2D) image.getGraphics();
//设置图片的背景颜色
g.setColor(Color.WHITE);
g.fillRect(0,0,80,20);
//给图片写数据
g.setColor(Color.BLUE);
g.setFont(new Font(null,Font.BOLD,20));
g.drawString(makeNum(),0,20);
//告诉浏览器,这个请求用图片的方式打开
resp.setContentType("image/jpeg");
//网站存在缓存,不让浏览器缓存
resp.setDateHeader("expires",-1);
resp.setHeader("Cache-Control","no-cache");
resp.setHeader("Pragma","no-cache");
//把图片写给浏览器
ImageIO.write(image,"jpg",resp.getOutputStream());
}
private String makeNum(){
Random random = new Random();
String num = random.nextInt(9999999)+"";
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < 7- num.length(); i++) {
stringBuffer.append("0");
}
num = stringBuffer.toString()+num;
return num;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
web.xml里注册servlet
<servlet>
<servlet-name>image</servlet-name>
<servlet-class>com.hs_vae.Demo02ImageServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>image</servlet-name>
<url-pattern>/image</url-pattern>
</servlet-mapping>
启动Tomcat,网址输入/image,每隔3秒自动更新验证码图片
4、实现重定向
一个web资源收到客户端请求后,它会通知客户端去访问另外一个web资源,这个过程叫重定向
public class Demo03RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/**
* resp.setHeader("Location","/resp/image");
* resp.setStatus(302);
*/
//重定向,需要带上项目的路径
resp.sendRedirect("/resp/image");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
重定向和转发的区别
相同点:页面都会实现跳转
不同点:
- 请求转发的时候,url不会产生变化 307
- 重定向时候,url地址栏会发生变化 302
案例:用户登陆重定向到另一个页面
在pom.xml中导入jsp依赖
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
创建实现类
public class Demo04Request extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//处理请求
String username = req.getParameter("username");
String password = req.getParameter("password");
//重定向,记得写上项目路径resp
resp.sendRedirect("/resp/success.jsp");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
在index.jsp中创建表单
<%--pageContext.request.contextPath代表当前项目--%>
<form action="${pageContext.request.contextPath}/login" method="post">
用户名: <input type="text" name="username"> <br>
密码: <input type="password" name="password"> <br>
<input type="submit">
</form>
注册servlet请求
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.hs_vae.Demo04Request</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
启动Tomcat,输入用户名和密码后点击提交,显示success
HttpServletResquest
HttpServletResquest代表客户端的请求,用户通过Http协议访问服务器,HTTP请求中的所有信息会被封装到HttpServletRequest,通过这个HttpServletRequest的方法,获得客户端的所有信息
1、获取前端传递的参数
创建一个实现类
public class Demo01Login extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求和回应的编码
resp.setCharacterEncoding("utf-8");
req.setCharacterEncoding("utf-8");
//获取请求的参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbys = req.getParameterValues("hobbys");
System.out.println(username);
System.out.println(password);
System.out.println(Arrays.toString(hobbys));
//通过请求转发,注意这里的/代表当前项目
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
在默认页面创建表格内容
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<h2>Hello World!</h2>
<form action="${pageContext.request.contextPath}/login" method="post">
用户名: <input type="text" name="username"> <br>
密码: <input type="password" name="password"> <br>
爱好:
<input type="checkbox" name="hobbys" value="唱歌">唱歌
<input type="checkbox" name="hobbys" value="上网">上网
<input type="checkbox" name="hobbys" value="运动">运动
<br>
<input type="submit">
</form>
</body>
</html>
在创建一个success.jsp文件,提交后跳转到该页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>Success</h1>
</body>
</html>
注册servlet
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.hs_vae.Demo01Login</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
启动Tomcat测试
点击提交后,映射路径为login,请求转发到创建好的success.jsp文件,页面显示success
服务日志输出了前端请求的参数,用户名、密码和爱好