6.Servlet
6.1 Servlet简介
- Servlet是sun公司开发的一门动态web技术
- sun在api中提供了一个接口:Servlet。开发需要实现此接口,并将其部署到web服务器中
- 总结:实现了Servlet接口的java程序叫Servlet
6.2 简单Servlet创建
-
Servlet接口有两个实现类GenericServlet,HttpServlet
-
Servlet接口
void init(ServletConfig var1) throws ServletException;
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
void destroy();
- GenericServlet类
public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
- HttpServlet实现了service方法,但需要自己是实现
构建一个普通maven项目,删掉src目录,在这个项目中建moduel,此项目为maven主工程
maven父子工程描述:父项目中有子项目关联
<modules>
<module>servlet-01</module>
</modules>
- 子项目中父项目关联
<parent>
<artifactId>web03</artifactId>
<groupId>com.zk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
- 父项目中jar子项目可以直接使用,继承多态的概念
maven环境友好
- 修改web.xml为最新配置
- 将maven项目结构搭建完整
编写serlet程序
- 实现servelt接口,直接继承HttpServlet
//get和post是不同的请求方式,可以互相调用
/* ServletInputStream inputStream = req.getInputStream();
BufferedReader reader = req.getReader();
ServletOutputStream outputStream = resp.getOutputStream();*/
PrintWriter writer = resp.getWriter();
writer.println("hello world!");
编写 Servlet映射
- 为什么需要:java程序有浏览器访问,浏览器链接web服务器,需要在web服务中注册servlet,需要个浏览器能访问的路径
<!--注册servlet-->
<servlet>
<servlet-name>helloS</servlet-name>
<servlet-class>com.zk.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet请求路径-->
<servlet-mapping>
<servlet-name>helloS</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
配置tomcat:配置项目发布的路径
启动测试
6.3 Servlet原理
- web服务器和web容器不是一个东西
- Servlet由web服务器调用,web服务器收到浏览器请求后会:
- web容器调用Service方法把这两个对象Request对象、Response对象传入该service方法,将Request对象到该service方法的实现类去处理,返回Response对象让容器获取,容器将Response返回给浏览器。
6.4 mappint映射问题
- 一个servlet可以指定一个映射路径
<!--注册servlet-->
<servlet>
<servlet-name>helloS</servlet-name>
<servlet-class>com.zk.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet请求路径-->
<servlet-mapping>
<servlet-name>helloS</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
- 一个servlet可以指定多个映射路径
<!--注册servlet-->
<servlet>
<servlet-name>helloS</servlet-name>
<servlet-class>com.zk.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet请求路径-->
<servlet-mapping>
<servlet-name>helloS</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>helloS</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
- 一个servlet可以指定通用映射路径,
<servlet-mapping>
<servlet-name>helloS</servlet-name>
<url-pattern>/hel/*</url-pattern>
</servlet-mapping>
- 默认请求路径,/*会优先于index.jsp进入servlet(尽量少用)
<servlet-mapping>
<servlet-name>helloS</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
- 一个servlet可以指定前缀或后缀映射路径
<!--/*.do报错,不能加项目映射路径/
v1/s2.do-->
<servlet-mapping>
<servlet-name>helloS</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
- 优先级问题:指定了固定映射路径的优先级最高,找不到找默认的处理请求
<servlet>
<servlet-name>error</servlet-name>
<servlet-class>com.zk.servlet.ErrorServlet</servlet-class>
</servlet>
<!--servlet请求路径-->
<servlet-mapping>
<servlet-name>error</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
6.5 ServletContext
- web容器启动时,会为每个web程序创建一个ServletContext对象,代表了当前web应用
this.getInitParameter(""); //获得参数信息 ServletConfig servletConfig = this.getServletConfig();//ServletConfig 配置 ServletContext servletContext = this.getServletContext(); //ServletContext上下文
<!--全局参数-->
<!--<context-param>
<param-name></param-name>
<param-value></param-value>
</context-param>-->
<servlet>
<servlet-name>testS</servlet-name>
<servlet-class>com.zk.servlet.TestServlet</servlet-class>
<!--携带参数-->
<!--<init-param>
<param-name></param-name>
<param-value></param-value>
</init-param>-->
</servlet>
- 设置响应编码
resp.setContentType("text/html;charset=utf-8");
6.5.1 共享数据:某个servlet保存数据,另一个servlet中拿到
- 存放ServletContext类
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("进入get方法!");
this.getInitParameter(""); //获得参数信息
ServletConfig servletConfig = this.getServletConfig();//ServletConfig 配置
ServletContext servletContext = this.getServletContext(); //ServletContext上下文
String name = "托尼";
servletContext.setAttribute("name",name);
}
- 获取ServletContext中值
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = (String)this.getServletContext().getAttribute("name");
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().println("参数:"+name);
}
- web.xml中映射配置
<servlet>
<servlet-name>testS</servlet-name>
<servlet-class>com.zk.servlet.TestServlet</servlet-class>
</servlet>
<!--servlet请求路径-->
<servlet-mapping>
<servlet-name>testS</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>getS</servlet-name>
<servlet-class>com.zk.servlet.GetServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getS</servlet-name>
<url-pattern>/getS</url-pattern>
</servlet-mapping>
- 启动测试。
6.5.2 存在问题
- 方式1:idea控制台启动tomcat时显示乱码问题:1.需要在tomcat文件conf设置
apache-tomcat-8.5.41\conf\logging.properties
java.util.logging.ConsoleHandler.encoding = GBK
- 方式2:idea控制台启动tomcat时显示乱码问题:2.help里有个VM选项idea64.exe.vmoptions。在里面加上-Dfile.encoding=UTF-8
idea设置文件编码步骤:File——>Settings——>Editor——>File Encodings,将三处编码格式改为UTF-8
- 重要的一步:服务器vm设置-Dfile.encoding=UTF-8
- 重新启动服务器,乱码纠正。
6.5.3 获取初始化参数
- web.xml中配置全局初始化参数
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost/mybatis</param-value>
</context-param>
- 创建servlet获取参数
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
ServletContext servletContext = this.getServletContext();
String url = servletContext.getInitParameter("url");
resp.getWriter().println("参数:"+url);
}
- 配置路径映射
<servlet>
<servlet-name>sd01</servlet-name>
<servlet-class>com.zk.servlet.ServletDemo01</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>sd01</servlet-name>
<url-pattern>/sd01</url-pattern>
</servlet-mapping>
6.5.4 请求转发
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
ServletContext servletContext = this.getServletContext();
RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/sd01"); //转发请求路径
requestDispatcher.forward(req,resp); //调用forward实现请求转发
}
- 转发:请求路径不变
- 重定向:请求路径发生变化
6.5.5 读取资源文件
- Properties:在java目录下新建properties文件;在resources目录下新建properties文件
- 都配打包到同一路径下,classes(类路径),叫classpath
- 通过ServletContext中的资源转流对象加载properties文件
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
ServletContext servletContext = this.getServletContext();
/*"/为当前web项目*/
InputStream is = servletContext.getResourceAsStream("/WEB-INF/classes/com/zk/servlet/test.properties");
Properties prop = new Properties();
prop.load(is);
String username = prop.getProperty("username");
String password = prop.getProperty("password");
resp.getWriter().println(username+"::"+password);
}
username=root
password=123456123456
#classpath类路径:target下的class路径=源码中的java和resource文件
- 进行访问测试
root::123456123456
6.6 HttpServletRequest
- HttpServletRequest代表客户端请求,用户通过http协议访问服务器,http请求中所有信息会封装到HttpServletRequest对象中,通过此对象的方法获得客户端请求的所有信息。
6.6.1 获取前端传递的参数
6.6.2 请求转发
- 请求转发映射的地址是localhost:8080/当前web目录,而重定向映射的地址是localhost:8080
- HttpServletRequest请求转发时,页面jsp里面就已经获取了/r传过来的
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//处理请求
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] loves = req.getParameterValues("love");
req.getSession().setAttribute("username",username);
req.getSession().setAttribute("password",password);
System.out.println(username+":"+password);
System.out.println(Arrays.toString(loves));
//重定向时注意路径问题,否则会出现404
//resp.sendRedirect("/s2/success.jsp");
//这个/代表web应用
req.getRequestDispatcher("/success.jsp").forward(req,resp);
6.7 HttpServletResponse
- web服务器接收到客户端的http请求,针对这个请求,分别创建一个请求对象HttpServletRequest,和一个响应对象HttpServletResponse
- 获取客户端请求的参数用:HttpServletRequest
- 给客户端响应信息用:HttpServletResponse
6.7.1 分类
- 负责向浏览器发送数据的方法
ServletOutputStream getOutputStream() throws IOException;//其他流,否则用PrintWriter导致字符串丢失
PrintWriter getWriter() throws IOException; //中文流
- 负责向浏览器发送响应头的方法
void setCharacterEncoding(String var1);
void setContentLength(int var1);
void setContentLengthLong(long 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);
- 响应的状态码
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;
6.7.2 常见应用
- 向浏览器输出信息
- 下载文件
获取下载文件的路径
下载的文件名是什么
设置浏览器支持下载的内容
获取下载文件输入流
创建缓冲区
获取OutputStream对象
将FileOutputStream流写入到buffer缓冲区
使用OutputStream将缓冲区中的数据输出到客户端
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("comeing fileServlet!");
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
ServletContext servletContext = this.getServletContext();
//String realPath = servletContext.getRealPath("/WEB-INF/classes/可达鸭.png");
String realPath = servletContext.getClassLoader().getResource("/可达鸭.png").getPath().replace("%20", " ");
System.out.println(realPath);
String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
//web下载文件的头部
System.out.println("realPath========"+realPath);
//D:\apache-tomcat-8.5.41\apache-tomcat-8.5.41\webapps\s2\可达鸭.png 无此图片
//URLEncoder.encode(fileName,"utf-8")对中文进行编码否则会乱码
resp.setHeader("Content-disposition", "attachment;filename="+ URLEncoder.encode(fileName,"utf-8"));
FileInputStream fis = new FileInputStream(realPath);
ServletOutputStream os = resp.getOutputStream();
int len = 0;
byte[] bytes = new byte[1024];
while ((len=fis.read(bytes))!=-1){
os.write(bytes,0,len);
}
os.close();
fis.close();
}
6.7.3 验证码功能
- 前端实现
- 后端实现,要用java图片类,产生一个图片
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//让浏览器4秒刷新一次
resp.setHeader("refresh","4");
//内存中创建一张图片
BufferedImage bi = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);
//得到画笔
Graphics g = bi.getGraphics();
//设置背景色
g.setColor(Color.white);
g.fillRect(0,0,80,20);
//给图片写数据
g.setColor(Color.cyan);
g.setFont(new Font(null,Font.ITALIC,20));
g.drawString(getRandom(),0,20);
//给浏览器设置响应格式
resp.setContentType("image/jpeg");
//设置浏览器不缓存
resp.setDateHeader("expires",-1);
resp.setHeader("Cache-Control","no-cache" );
resp.setHeader("Pragma","no-cache");
ImageIO.write(bi, "jpg", resp.getOutputStream());
}
public static String getRandom(){
Random random = new Random();
String num = String.valueOf(random.nextInt(9999));
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < 4-num.length(); i++) {
stringBuffer.append("0");
}
return stringBuffer.toString() + num;
}
6.7.4 HttpServletResponse重定向
- 一个web资源B收到A请求后,B会通知A去访问另一个web资源C,此过程成为重定向
- 场景:用户登录
void sendRedirect(String var1) throws IOException;
- 重定向因为可能会跳转到不是该web项目下的链接,所以不自动加上下文是正常的
resp.sendRedirect("/s2/is");
//等效
/*resp.setHeader("Location","/s2/is");
resp.setStatus(HttpServletResponse.SC_FOUND);*/
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
//处理请求
String username = req.getParameter("username");
String password = req.getParameter("password");
req.getSession().setAttribute("username",username);
req.getSession().setAttribute("password",password);
System.out.println(username+":"+password);
//重定向时注意路径问题,否则会出现404
resp.sendRedirect("/s2/success.jsp");
}
<%--login.jsp-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<h2>Hello World!</h2>
<%--${pageContext.request.contextPath}当前项目路径--%>
<form action="<%=this.getServletConfig().getServletContext().getContextPath()%>/login" method="get">
账号:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" name="提交">
</form>
</body>
</html>
<%--success.jsp-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>success</title>
</head>
<body>
<h2>主页面</h2>
username:<%=session.getAttribute("username")%><br>
password:<%=session.getAttribute("password")%><br>
</body>
</html>
6.8 转发和重定向区别
相同点
- 页面都会实现跳转
不同点
- 转发时,请求路径不改变,请求转发是内部跳转;307
- 重定向,请求路径改变;302
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/123949.html