Servlet
Servlet简介
- 开发动态web的一门技术
- 作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层,即接收客户端发送过来的请求并且响应数据给客户端。
- Sun公司在API中提供了一个接口:Servlet; 开发Servlet程序只需要完成两个小步骤:
- 编写一个类实现Servlet接口;
- 把开发号的Javalei部署至web服务器中;
把实现了Servlet接口的Java程序叫做Servlet
配置Servlet
-
新建一个Maven-webapp项目, 在pom.xml中添加依赖:
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.3</version> <scope>provided</scope> </dependency>
-
新建一个Java类继承
HttpServlet
, 重写并实现方法, 如;public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { System.out.println("进入了DoGet方法"); PrintWriter writer = resp.getWriter();//响应流 writer.println("hello servlet"); } //get或者post业务逻辑相同,只是请求方法不同, 可以互相调用 @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { this.doGet(req, resp); } }
-
编写Servlet映射
原因: Java程序不能直接在浏览器中访问, 而浏览器链接web服务器, 所以需要在web服务器中注册写的Servlet, 并提供一个浏览器能够访问的路径;
-
使用最新的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>
-
在web.xml中配置Servlet访问地址:
<!-- 给tomcat配置servlet相关信息 --> <servlet> <!-- 写明servlet的名字(一般使用类名即可) --> <servlet-name>MyServlet</servlet-name> <!-- 写明servlet的全类名 --> <servlet-class>servlet.MyServlet</servlet-class> </servlet> <!-- 给servlet配置访问地址 --> <servlet-mapping> <!-- 写明需要配置访问地址的servlet --> <servlet-name>MyServlet</servlet-name> <!-- 写明为该servlet配置的访问地址 --> <url-pattern>/myServlet</url-pattern> </servlet-mapping>
<url-pattern>/myServlet</url-pattern>
标签中/
的作用:相当于拼接到http://ip:port/工程路径
后,即http://ip:port/工程路径/myServlet
-
-
配置Tomcat
检查这些选项:
Servlet原理
Servlet是由服务器调用, web服务器在收到浏览器请求后, 会:
mapping相关注意点
-
一个Servlet请求可以指定一个映射路径
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/helloServlet</url-pattern> </servlet-mapping>
-
一个Servlet请求可以指定多个映射路径
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/helloServlet1</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/helloServlet2</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/helloServlet3</url-pattern> </servlet-mapping>
-
一个Servlet请求可以指定通用映射路径
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/helloServlet/*</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>*.do</url-pattern> </servlet-mapping> <!-- *.do前不能加任何请求路径 -->
-
优先级问题
指固有的映射路径优先级最高, 找不到则会走默认的处理请求(/*);
ServletContext
web容器在启动时, 会为每个web程序都创建一个对相应的ServletContext对象, 它代表了当前的web应用;
1.共享数据:
在一个Servlet中的数据可在另一个Servlet中拿到;
-
创建一个放置数据的类
public class CreateC extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = getServletContext(); servletContext.setAttribute("username","Loki");//将数据以键值对的形式保存在了ServletContext中,名为username, 值为"Loki" } }
-
创建获取数据的类
public class GetC extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = getServletContext(); String username=(String) servletContext.getAttribute("username"); //防止中文乱码 resp.setContentType("text/html"); resp.setCharacterEncoding("utf-8"); resp.getWriter().println("名字:"+username); } }
-
web.xml中注册
<servlet> <servlet-name>createc</servlet-name> <servlet-class>CreateC</servlet-class> </servlet> <servlet-mapping> <servlet-name>createc</servlet-name> <url-pattern>/createc</url-pattern> </servlet-mapping> <servlet> <servlet-name>getc</servlet-name> <servlet-class>GetC</servlet-class> </servlet> <servlet-mapping> <servlet-name>getc</servlet-name> <url-pattern>/getc</url-pattern> </servlet-mapping> <servlet>
运行测试:
1.直接获取ServletContext
2.先输入createC再访问此地址
2.获取初始化参数
<!-- 设定一些web参数 -->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context=this.getServletContext();
String url = context.getInitParameter("url");
resp.getWriter().print(url);
}
运行结果: 浏览器中输出了url参数的值
3.请求转发
<servlet>
<servlet-name>Dispatcher</servlet-name>
<servlet-class>Dispatcher</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Dispatcher</servlet-name>
<url-pattern>/dispatcher</url-pattern>
</servlet-mapping>
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = getServletContext();
System.out.println("转发");
//RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/createc");
//requestDispatcher.forward(req,resp);
servletContext.getRequestDispatcher("/createc").forward(req,resp);
}
请求转发地址不变
4.读取资源文件
-
创建properties文件
-
maven先执行clean, 再启动Tomcat, 找到target中的地址 (类路径)
-
编写类实现读取db.properties
public class PropertiesServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doGet(req,resp); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties"); Properties prop = new Properties(); prop.load(is); String username = prop.getProperty("username"); String password = prop.getProperty("password"); resp.getWriter().println(username+':'+password); } }
-
添加映射
<servlet> <servlet-name>Prop</servlet-name> <servlet-class>com.andrew.context.PropertiesServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Prop</servlet-name> <url-pattern>/prop</url-pattern> </servlet-mapping>
运行结果
HttpServletResponse
web服务器接受到客户端的http请求, 针对这个请求, 分别创建一个代表请求的HttpServletRequest对象, 代表相应的HttpServletResponse对象;
- 如果要获取客户端的请求过来的参数, 找HttpServletRequest
- 如果要给客户端响应一些信息, 找HttpServletResponse
1.简单分类
负责向浏览器发送数据的方法
ServletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() throws IOException;
负责向浏览器发送响应头的方法
void setCharacterEncoding(String var1);
void setContentLength(int var1);
void setContentType(String var1);
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);
常见响应的状态码
- 200:表示请求成功
- 302:表示请求重定向
- 404:表示服务器找不到该请求地址(地址有错)
- 500:表示服务器内部错误(代码有错)
2.常见应用
-
向浏览器输出消息
-
下载文件
- 获取下载文件的路径
-
确定下载的文件名
- 设置使浏览器能够下载我们需要的文件
-
获取下载文件的输入流
- 创建缓冲区
- 获取
OutputStream
对象 - 将
FlieOutputStream
流写入buffer缓冲区 - 使用
OutputStream
将缓冲区中的数据输出到客户端
重定向:一个web资源B收到客户端A的请求后,它B会通知A客户端去访问另一个web资源C,这个过程叫重定向
/* 重定向的原理 resp.setHeader("Location","/r/img"); resp.setStatus(302); */ resp.sendRedirect("/r/img");
3.中文乱码问题
// 指定服务器编码
resp.setCharacterEncoding("UTF-8");
// 指定客户端编码
resp.setHeader("Content-type","text/html;charset=UTF-8");
HttpServletRequest
HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器,HTTP请求中的所有信息会被封装到HttpServletRequest中
HttpServletRequest对象:主要作用是用来接收客户端发送过来的请求信息
例如:请求的参数,发送的头信息等都属于客户端发来的信息
1.获取请求行数据
- 获取虚拟目录:也就是tomcat中的虚拟目录,例如/r
String getContextPath()
- 获取Servlet路径: 就是在web.xml中注册的servlet映射,例如/hello
String getServletPath()
- 获取请求URI:/s1/hello
String getRequestURI():
/s1/helloStringBuffer getRequestURL()
http://localhost/s1/hello
2.获取请求参数
req.getParameter(String name)
:根据参数名称获取参数值req.getParameterValues(String name)
:根据参数名称获取参数值的数组
3.中文乱码问题
req.setCharacterEncoding("utf-8")
- get方式:tomcat 8 已经将get方式乱码问题解决了
- post方式:会乱码
- 解决在获取参数前,设置req的编码
req.setCharacterEncoding("utf-8")
- 解决在获取参数前,设置req的编码
req.setCharacterEncoding("utf-8");
4.请求转发
请求转发,是一种服务器的行为,当客户端请求到达后,服务器进行转发,此时会将请求对象进行保存,地址栏中的URL地址不会变,得到相应后,服务器再将响应发送给客户端,从始至终只有一个请求发出,request数据可以共享
步骤:
- 通过request对象获取请求转发器对象:
getRequestDispatcher(String path)
- 使用RequestDispatcher对象来进行转发:
forward(ServletRequest request, ServletResponse response)
req.getRequestDispatcher("/gp").forward(req,resp);
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
</head>
<body>
<h1>登录</h1>
<div style="text-align: center">
<%-- 这里表单表示的意思:以post方式提交表单,提交到我们的login请求--%>
<%-- ${pageContext.request.contextPath}代表我们的web项目--%>
<form action="${pageContext.request.contextPath}/login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
爱好:
<input type="checkbox" name="hobbies" value="女孩">女孩
<input type="checkbox" name="hobbies" value="代码">代码
<input type="checkbox" name="hobbies" value="唱歌">唱歌
<input type="checkbox" name="hobbies" value="电影">电影
<br>
<input type="submit">
</form>
</div>
</body>
</html>
LoginServlet.java
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 password = req.getParameter("password");
String[] hobbies = req.getParameterValues("hobbies");
System.out.println("----------------");
System.out.println(username);
System.out.println(password);
System.out.println(Arrays.toString(hobbies));
System.out.println("----------------");
// 通过请求转发
// 这里的 / 代表当前的web应用
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
作业: Servlet 用户登录界面简单实现
实现的功能:
- 含有登陆: 注册页面、其他页面。
- 登录功能:手动输入信息,符合已存在的用户信息则成功登录。
- 注册功能:手动输入信息,不能重复注册已存在的用户名,否则注册失败。
- 用户展示:在页面上展示所有已经注册的用户的信息。
- 登陆过滤:其他页面,只有登陆成功后才可访问,否则跳转至登陆页面。
图:
运行测试:
-
启动Tomcat, 弹出网页
-
点击"用户信息", 会显示数据库中的所有用户名及密码
-
在"用户名"一栏中输入错误的用户名,点击"提交", 停在该页面并显示错误信息
-
输入正确的用户名, 但输入错误的密码,点击"提交"
-
输入正确的用户名及密码, 点击"提交":跳转到另一网页
-
输入已存在的用户名,点击"注册"
-
输入可用用户名和密码, 点击在"注册"
再点击用户信息, 已经更新
数据库中:
出现的问题:
-
maven项目创建后没有自动生成
.iml
文件;解决:
在Idea中的Terminal里输入命令:
mvn idea:module
-
Tomcat部署工件出错, 如图:
解决:
发现是地址中未以
/
开头, 补上即可正常运行; -
运行tomcat服务器下,在项目中修改CSS文件,刷新页面不更新样式;
解决:
浏览器会缓存CSS\JS文件,在浏览器按F12打开开发者调试工具,点击右上角展开选项,选择settings,勾选图中选项,禁止缓存;
-
JSP中一个表单中的两个按钮但分别执行两个action;
解决:
form标签中的action为空, 在submit标签中加入如下语句:
-
在catch语句中加入return语句方法不能退出;
原因:在正常情况(即程序正常执行try catch finally语句块,不会在语句中出现退出程序、线程终止等特殊情况)下,都会执行finally语句块,如果finally中有return,则程序会走finally中的return,如果没有,则先执行try或者catch中的return,将其存入临时栈中,执行完finally语句后才返回临时栈中的值。
解决:加入对应返回值的临时变量, 在catch中对其赋值;
-
如何在网页中回显后端传的值;
解决:
利用set\getAttribute实现:
在jsp中(
<% %>
) -
HTTP404
解决:
url-pattern 大小写敏感
参考: