目录

Servlet原理及其使用

什么是Servlet

是JAVA的基于WEB服务器的完成动态网页开发的一种技术

Servlet的使用

编写一个Servlet,使用继承HttpServlet的方式

  1. package com.it.servlet;
  2. import javax.servlet.ServletException;
  3. import javax.servlet.http.*;
  4. import java.io.IOException;
  5. public class MyFirstServlet extends HttpServlet {
  6. @Override
  7. protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  8. // 获取表单提交的参数,填写的参数是表单对应数据的name属性
  9. String username = req.getParameter("username");
  10. String password = req.getParameter("password");
  11. if(username.equals("dqx") && password.equals("123")) {
  12. // 转发到/success.jsp
  13. req.getRequestDispatcher("/success.jsp").forward(req,resp);
  14. }else {
  15. // 在request作用域中存入一个 key value
  16. req.setAttribute("msg", "用户名或密码错误");
  17. req.getRequestDispatcher("/login.jsp").forward(req, resp);
  18. }
  19. }
  20. }

配置web.xml

  1. <servlet>
  2. <servlet-name>loginServlet</servlet-name>
  3. <servlet-class>com.it.servlet.MyFirstServlet</servlet-class>
  4. <!-- 配置在服务器启动时加载Servlet -->
  5. <load-on-startup>0</load-on-startup>
  6. </servlet>
  7. <servlet-mapping>
  8. <servlet-name>loginServlet</servlet-name>
  9. <!-- 处理的请求 -->
  10. <url-pattern>/doLogin</url-pattern>
  11. </servlet-mapping>

很简单的几个JSP文件

  • login.jsp
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <!DOCTYPE html>
  3. <html lang="zh-CN">
  4. <head>
  5. <%
  6. String path = request.getContextPath();
  7. String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
  8. %>
  9. <base href="<%=basePath%>">
  10. </head>
  11. <body>
  12. <form action="doLogin" method="post">
  13. <%
  14. String msg = (String) request.getAttribute("msg");
  15. System.out.println("---------");
  16. if(msg != null) {
  17. out.print(msg);
  18. }
  19. %>
  20. <hr>
  21. 用户名:<input type="text" name="username"> <br>
  22. 密码:<input type="password" name="password"> <br>
  23. <input type="submit" value="登录">
  24. </form>
  25. </body>
  26. </html>
  • success.jsp
  1. <h1>登录成功</h1>

小提示,如果继承HttpServlet发现找不到类的时候,引入一个jar包添加到类路径(必须放在WEB-INF目录下)



——————————————————————————————————

Servlet读取配置(自身Servlet配置、全局配置)

为什么需要读取配置?

答:因为有些配置是固定的(例如编码),许多地方都要使用到,而如果硬编码的话,一旦编码改变,则需要更改多处,影响维护。

获得Servlet自己的配置信息

  • 在web.xml中配置参数
  1. <servlet>
  2. <servlet-name>myConfigServlet</servlet-name>
  3. <servlet-class>com.it.servlet.MyConfigServlet</servlet-class>
  4. <!-- 配置Servlet配置参数 -->
  5. <init-param>
  6. <param-name>charset</param-name>
  7. <param-value>UTF-8</param-value>
  8. </init-param>
  9. </servlet>
  • 在Servlet中获取配置信息(可以在构造函数、init()方法、等等地方都能获取到)
  1. public class MyConfigServlet extends HttpServlet {
  2. private String charset;
  3. @Override
  4. public void init() throws ServletException {
  5. // 获得Servlet参数,这两种方式是一样的
  6. charset = this.getInitParameter("charset");
  7. charset = this.getServletConfig().getInitParameter("charset");
  8. }

获得全局配置信息

  • 在web.xml中配置全局参数
  1. <context-param>
  2. <param-name>globalCharset</param-name>
  3. <param-value>GBK</param-value>
  4. </context-param>
  • 在Servlet中获取
  1. public class MyConfigServlet extends HttpServlet {
  2. private String globalCharset;
  3. @Override
  4. public void init() throws ServletException {
  5. // 获得全局配置参数
  6. globalCharset = this.getServletContext().getInitParameter("globalCharset");
  7. System.out.println(globalCharset);
  8. }

解决HTTP请求当中的乱码问题(get、post、response)

response响应乱码

  • response响应乱码出现的原因?

    答:由于浏览器不知道服务器响应的内容是什么编码的,浏览器默认使用GBK编码,而如果服务器响应的数据是不是GBK编码的时候,浏览器就会乱码
  • 解决方法

    答:在响应中告知浏览器以什么编码来解析数据
  1. // 注意,这里是因为演示,所以硬编码了,实际编码应该从配置中读取
  2. // 这句话就是告知浏览器接收到响应数据时以何种类型处理,以何种编码解析
  3. resp.setContentType("text/html;charset=UTF-8");

post请求时接收参数乱码

  • post请求出现乱码的原因

    答:浏览器进行post请求时(表单提交),浏览器的页面编码与服务器接收处理参数的编码不一致时,就会出现乱码。
  • 解决方法,设置request处理请求参数的编码
  1. request.setCharacterEncoding("UTF-8");

get请求时,接收浏览器的url中的参数时乱码

  • get请求出现乱码的原因

    答:浏览器进行get请求(参数是在URI上)时,浏览器的页面编码(例如浏览器该页面是UTF-8编码)与服务器接收处理URI参数的编码(tomcat默认是IOS-8895-1)不一致时,就会出现乱码。
  • 解决方案有2种
    • 通过修改tomcat服务器中的conf目录中的server.xml文件,添加URIEncoding配置
    1. <Connector port="8080" protocol="HTTP/1.1"
    2. connectionTimeout="20000"
    3. redirectPort="8443" URIEncoding="utf-8" />
    • 在接受参数后,将数据转换为与页面提交的数据一致的编码
    1. byte[] bytes = username.getBytes("ISO-8859-1");
    2. String newUsername = new String(bytes,"UTF-8");

Servlet的注解支持(代替xml配置servlet方式)

可以在Servlet类上使用注解的方式代替在web.xml中的配置

  1. import javax.servlet.annotation.WebInitParam;
  2. import javax.servlet.annotation.WebServlet;
  3. import javax.servlet.http.HttpServlet;
  4. @WebServlet(loadOnStartup = 0,
  5. initParams = {@WebInitParam(name = "charset",value = "UTF-8"),@WebInitParam(name = "key2",value = "value2")},
  6. urlPatterns = "/AnnoServlet")
  7. public class AnnoServlet extends HttpServlet {
  8. }

Servlet的原理

Servlet的响应原理

  • 浏览器发送请求到服务器
  • 服务器通过web.xml中配置的servlet-mapping找到对应的映射
  • 通过匹配到映射找到对应的servlet,通过反射创建其对象
  • 调用该对象中的service方法处理请求
  • 处理请求后使用将响应结果传输给浏览器

Servlet的生命周期

  • 类加载(Servlet加载)
  • 实例化(利用反射创建对象,单例)
  • init初始化
  • service 处理请求
  • destroy 销毁

Servlet的加载时机

  • 在Servlet第一次处理请求时加载(默认)
  • 在服务器启动时就进行加载,在web.xml中对应的servlet标签中添加load-on-startup标签(一般值为0-10),优先级从大到小

Servlet的API关系

  • javax.servlet.Servlet接口
  • javax.servlet.GenericServlet 抽象类,实现了Servlet接口
  • javax.servlet.http.HttpServlet 普通类,继承了GenericServlet抽象类

    所以,想要编写一个Servlet必须要实现或者间接实现Servlet接口,一般使用最多的就是继承HttpServlet
  • 常用方法
  1. // Servlet接口中的方法
  2. void service(ServletRequest var1, ServletResponse var2);//核心方法,用于处理浏览器发送的请求
  3. ServletConfig getServletConfig(); //用于获取Servlet的配置信息

为什么继承了HTTPServlet不重写Service访问时会出现405报错?

答:因为继承了HTTPServlet方法没有重写service()方法或doGet()、doPost()方法

HTTPServlet为什么要这么处理?

答:因为本身我们开发者编写一个Servlet类就是为了处理请求,而既没有service()方法处理请求,也没有doGet()、doPost(),那这个Servlet存在的意义就缺失了。所以HttpServlet处理时就直接报错,是为了告知调用者重写service()或者doGet()、doPost()等方法

为什么service()方法是处理请求的,但是重写doGet、doPost()等方法也有效?
  • HttpServlet中通过获得请求的方式(get、post)后,还是会调用doGet、doPost等方法
  • 如果继承了HttpServlet的类重写了doGet方法,那么最后HttpServlet中的service方法在执行时判断了请求的方式是get请求后,会执行子类重写的doGet方法(多态)。

Servlet运行的Web项目中的4种路径问题

1、绝对路径(访问任何资源)

  1. // 格式: 协议://IP地址:端口号/资源路径
  2. <a href="http://127.0.0.1:8080/myProject1/path1/update.jsp">同一个项目下同一个文件夹中的文件update.jsp</a> <br/>
  3. <a href="http://127.0.0.1:8080/myProject1/path1/subpath/delete.jsp">同一个项目下同子文件夹中的文件delete.jsp</a> <br/>
  4. <a href="http://127.0.0.1:8080/myProject1/path2/add.jsp">同一个项目下同级文件夹中的文件add.jsp</a> <br/>
  5. <a href="http://127.0.0.1:8080/myProject1/index.jsp">同一个项目下父级文件夹中的文件index.jsp</a> <br/>
  6. <a href="http://127.0.0.1:8080/myProject1/servlet/DoLogin2">访问servlet的路径</a> <br/>
  7. <a href="http://127.0.0.1:8080/myProject1/index.jsp">同一个服务器中不同项目中的文件servlet01/index.jsp</a> <br/>
  8. <a href="http://192.168.121.33:8080/demo/a.jsp">同一个局域网中不同服务器中的项目</a> <br/>
  9. <a href="http://www.baidu.com">外网服务器的项目</a> <br/>

2、根路径(访问当前服务器的任何资源)

提示:只能访问当前服务器的任何资源

  1. <a href="/webdemo01/path1/update.jsp">同一个项目下同一个文件夹中的文件update.jsp</a> <br/>
  2. <a href="/webdemo01/path1/subpath/delete.jsp">同一个项目下同子文件夹中的文件delete.jsp</a> <br/>
  3. <a href="/webdemo01/path2/add.jsp">同一个项目下同级文件夹中的文件add.jsp</a> <br/>
  4. <a href="/webdemo01/index.jsp">同一个项目下父级文件夹中的文件index.jsp</a> <br/>
  5. <a href="/webdemo01/servlet/DoLogin2">访问servlet的路径</a> <br/>
  6. <a href="/webdemo01/index.jsp">同一个服务器中不同项目中的文件servlet01/index.jsp</a> <br/>
  7. <%--不行--%>
  8. <a href="/demo/a.jsp">同一个局域网中不同服务器中的项目</a> <br/>

3、相对路径(访问当前服务器的资源)、不推荐

  1. <a href="update.jsp">同一个项目下同一个文件夹中的文件update.jsp</a> <br/>
  2. <a href="subpath/delete.jsp">同一个项目下同子文件夹中的文件delete.jsp</a> <br/>
  3. <a href="../path2/add.jsp">同一个项目下同级文件夹中的文件add.jsp</a> <br/>
  4. <a href="../index.jsp">同一个项目下父级文件夹中的文件index.jsp</a> <br/>
  5. <a href="../servlet/DoLogin2">访问servlet的路径</a> <br/>
  6. <a href="../../myProject2/index.jsp">同一个服务器中不同项目中的文件

4、相对路径(基于base标签,访问当前项目,其实实质还是绝对路径或根路径)

  1. <head>
  2. <%
  3. // 这是绝对路径的base标签
  4. String path = request.getContextPath();
  5. String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
  6. // 根路径的base标签
  7. String genBasePath = request.getContextPath() + "/";
  8. %>
  9. <base href="<%=genBasePath%>">
  10. </head>
  11. <body>
  12. <%-- 注意,这里不要在写一个/了,不然就变成根路径与base标签无关了了 --%>
  13. <a href="index.jsp">访问index.jsp</a>
  14. </body>

使用idea配置模板

不同路径的使用场景

  • 路径适用于jsp页面中的 a、form、src、link等等
  • 访问其他服务器时:绝对路径
  • 访问自己服务器其他项目时: 根路径
  • 访问当前项目:base路径

转发与重定向的原理及区别

原理不同

  • 转发,指的是在服务器跳转

    服务器在内部接收到第一个请求时,转发到其他servlet或页面处理,然后返回数据给用户。

    这个过程用户是不可见的,所以转发时,浏览器只会向服务器发出一个请求

  • 重定向,客户端跳转

    服务器在运行到重定向的语句时,将重定向请求发回给浏览器,其状态码为302(并携带者需要重定向的资源路径)

    浏览器在接收到这个302的重定向响应后,用其中的资源路径地址再次向服务器发送一个请求

    所以这个过程中涉及到了2个请求。所以重定向是用户可见的。

语法实现方式不同

  1. // 转发(这里使用的是相对路径)
  2. req.getRequestDispatcher("index.jsp").forward(req, resp);
  3. // 重定向(这里使用的是相对路径)
  4. resp.sendRedirect("index.jsp");

获取request作用域数据问题

转发能够获取request作用域中的数据,因为其转发的原理就是至始至终都只有一个请求,而request作用域的范围就是一个请求当中,所以能够获取

重定向不能获取request中的数据,因为重定向时,涉及到了2个请求,所以第二个请求已经不在第一个请求的作用范围内了,所以无法获取。

跳转页面后,网址的显示不同

转发跳转后,由于是服务器内部跳转,浏览器无法察觉,所以还是显示的浏览器访问的资源路径。

重定向跳转后,由于是客户端跳转,跳转对浏览器是可见的,所以显示的路径是重定向的路径。

书写代码时,使用“ / ”的意义不同

转发时候的字符串时候由于路径最前面会加上/项目名,所以写 / 代表着当前项目,这也意味着。转发只能转发到当前的项目资源。

支持书写的路径不同

  • 绝对路径
  • 转发:不支持
  • 重定向:支持
  • 相对路径(不推荐)
  • 转发:支持
  • 重定向:支持
  • 根路径
  • 转发:支持(当前项目)
  • 重定向:支持(代表当前服务器,与在jsp中使用根路径是一样的)

使用表单时重复提交问题

转发:会出现表单重复提交的问题,在提交表单时使用转发,在转发后的页面,如果刷新网页,就会重复提交表单。(所以提交表单推荐使用重定向)

重定向:不会出现重复提交表单的问题

效率问题

转发:效率更高(服务器只用处理一个请求)

重定向:效率低,因为浏览器发送了2个请求,服务器响应2个请求

是否经过配置的过滤器

转发:不会,因为是在服务器内部,请求刚进来的时候就已经经过了过滤器,不会再重复执行过滤器

重定向:会,因为是2个请求。

Request请求与Response响应的更多方法

Request的更多方法

  1. /* 获取请求头信息******/
  2. Enumeration headerNames = req.getHeaderNames();
  3. while (headerNames.hasMoreElements()) {
  4. String headerName = headerNames.nextElement();
  5. String headerValue = req.getHeader(headerName);
  6. System.out.println(headerName + "----" + headerValue);
  7. }
  8. System.out.println("-----------------------------------------");
  9. /*****获得URL地址信息******/
  10. // 获得协议:HTTP
  11. String scheme = req.getScheme();
  12. System.out.println(scheme);
  13. // 获得服务器IP : 127.0.0.1
  14. String serverName = req.getServerName();
  15. System.out.println(serverName);
  16. // 获得端口 : 8080
  17. int serverPort = req.getServerPort();
  18. System.out.println(serverPort);
  19. // 获得项目名 /servlet01
  20. String contextPath = req.getContextPath();
  21. System.out.println(contextPath);
  22. // 获得请求的服务路径,用根路径表示: /info
  23. String servletPath = req.getServletPath();
  24. System.out.println(servletPath);
  25. // 请求方式:GET
  26. String method = req.getMethod();
  27. System.out.println(method);
  28. // http://localhost:8080/servlet01/info
  29. String s = req.getRequestURL().toString();
  30. System.out.println(s);
  31. // :/servlet01/info
  32. String requestURI = req.getRequestURI();
  33. System.out.println(requestURI);
  34. /*****获取数据******/
  35. // 获取表单提交的数据
  36. String username = req.getParameter("username");
  37. // 获取request作用域中的数据
  38. Object user = req.getAttribute("user");
  39. // 获取多个name相同的参数
  40. String[] hobbies = req.getParameterValues("hobby");
  41. /*****获得浏览器信息和服务器信息******/
  42. // 获得远程访问服务器的客户端IP
  43. String remoteAddr = req.getRemoteAddr();
  44. System.out.println("访问者的IP为:" + remoteAddr);
  45. // 获得远程访问服务器的主机名
  46. String remoteHost = req.getRemoteHost();
  47. System.out.println(remoteHost);
  48. // 获得远程访问服务器的端口
  49. int remotePort = req.getRemotePort();
  50. System.out.println(remotePort);
  51. // 以下为获取本地
  52. String localAddr = req.getLocalAddr();
  53. String localName = req.getLocalName();
  54. int localPort = req.getLocalPort();
  55. /*****获取其他对象******(重点)*/
  56. // 获得session对象
  57. HttpSession session = req.getSession();
  58. // 获取请求Cookie
  59. Cookie[] cookies = req.getCookies();
  60. // 获得Servlet全局对象
  61. ServletContext servletContext = req.getServletContext();
  62. ServletContext servletContext1 = this.getServletContext();

Response的更多方法

  1. /******response的更多方法*******/
  2. // 设置contentType解决响应乱码
  3. resp.setContentType("text/html;charset=utf-8");
  4. // 设置响应编码
  5. resp.setContentType("UTF-8");
  6. // 设置文本长度(文件下载时用到)
  7. resp.setContentLength(1024);
  8. // 添加响应头信息,重复的头信息不会覆盖
  9. resp.addHeader("head1","value1");
  10. resp.addHeader("head1","value1");
  11. // 设置响应头信息,name一致会覆盖,这就是与addHeader的区别
  12. resp.setHeader("head2","hah");
  13. resp.setHeader("head2","hah2");
  14. // 添加Cookie
  15. resp.addCookie(new Cookie("cookie1","value1"));

小提示,如何在项目中访问到Servlet

其实每编写一个Servlet并使用web.xml配置好、或者使用注解的方式配置了一个Servlet时。

就相当于在Web根路径下放入了这个Servlet。



JAVAWEB - Servlet原理及其使用>从零开始学JAVA系列的更多相关文章

  1. JSP的执行原理、JSP的内置对象、四大作用域解析、MVC模式理解>从零开始学JAVA系列

    目录 JSP的执行原理.JSP的内置对象.四大作用域解析.MVC模式理解 JSP的执行原理 这里拿一个小例子来解析JSP是如何被访问到的 首先将该项目部署到tomcat,并且通过tomcat启动 通过 ...

  2. JAVAWEB过滤器、监听器的作用及使用>从零开始学JAVA系列

    目录 JAVAWEB过滤器.拦截器的作用及使用 过滤器Filter 什么是过滤器 为什么要使用过滤器(过滤器所能解决的问题) 配置一个过滤器完成编码的过滤 编写一个EncodingFilter(名称自 ...

  3. Session与Cookie的原理以及使用小案例>从零开始学JAVA系列

    目录 Session与Cookie的原理以及使用小案例 Cookie和Session所解决的问题 Session与Cookie的原理 Cookie的原理 Cookie的失效时机 小提示 Session ...

  4. JAVAWEB的基本入门(JSP、Tomcat)>从零开始学JAVA系列

    目录 JAVAWEB的基本入门(JSP.Tomcat) 使用idea创建web项目的两种方式 1.直接创建一个web项目(这样创建好的项目可以直接运行) 2.创建一个普通的java项目并配置web模块 ...

  5. spring框架的学习->从零开始学JAVA系列

    目录 Spring框架的学习 框架的概念 框架的使用 Spring框架的引入 概念 作用 内容 SpringIOC的学习 概念 作用 基本使用流程 SpringIOC创建对象的三种方式 通过构造器方式 ...

  6. 冒泡排序、选择排序、直接插入排序、快速排序、折半查找>从零开始学JAVA系列

    目录 冒泡排序.选择排序.直接插入排序 冒泡排序 选择排序 选择排序与冒泡排序的注意事项 小案例,使用选择排序完成对对象的排序 直接插入排序(插入排序) 快速排序(比较排序中效率最高的一种排序) 折半 ...

  7. JAVA数组的基础入门>从零开始学java系列

    目录 JAVA数组的基础入门 什么是数组,什么情况下使用数组 数组的创建方式 获取数组的数据 数组的内存模型 为什么数组查询修改快,而增删慢? 查询快的原因 增删慢的原因 数组的两种遍历方式以及区别 ...

  8. JAVA虚拟机的组成>从零开始学java系列

    目录 JAVA虚拟机的组成 什么是虚拟机? JAVA虚拟机的组成部分 堆区(堆内存) 方法区 虚拟机栈 本地方法栈 程序计数器 字符串常量池 JAVA虚拟机的组成 什么是虚拟机? 虚拟机是运行在隔离环 ...

  9. IDEA使用Tomcat时控制台乱码的解决方案>从零开始学JAVA系列

    IDEA使用Tomcat时控制台乱码的解决方案 解决方案1,修改启动时虚拟机参数 解决方案2,修改idea的设置 解决方案3,修改idea配置文件 在最后添加一行 '-Dfile.encoding=U ...

随机推荐

  1. gRPC入门—golang实现

    1.RPC 1.1 什么是RPC RPC(Remote Procedure Call),即远程过程调用,过程就是方法,简单来说,它就是一种能够像调用本地方法一样调用远程计算机进程中的方法的技术,在这种 ...

  2. 无法在源“”处找到包“entityframework”

    当在程序包管理器控制台安装ef时出现这个 出现这种情况可能是程序包源不对 我的是由于之前项目的源有一个内网平台的,把这个取消勾选就能安装成功了 上图设置路径为工具-NuGet包管理器-管理解决方案的N ...

  3. Jenkins CI&CD 自动化发布项目实战(下篇)

    Jenkins CI&CD 自动化发布项目实战(下篇) 作者 刘畅 时间 2020-12-04 实验环境 centos7.5 主机名 ip 服务配置 软件 gitlab 172.16.1.71 ...

  4. CentOS-磁盘扩容挂载目录

    挂载 查看存储情况 $ df -kh 查看磁盘情况 $ fdisk -l fdisk创建分区(注:可操作存储上限为2TB)$ fdisk /dev/sdb根据提示,依次输入"n", ...

  5. MySQL 插入中文后,显示为空白

    https://blog.csdn.net/sun_hj_95/article/details/79488583 在MySQL中插入中文后,显示如下: 解决方案: 在my.ini (在MySQL的安装 ...

  6. 经典论文系列 | 目标检测--CornerNet & 又名 anchor boxes的缺陷

    ​ 前言: 目标检测的预测框经过了滑动窗口.selective search.RPN.anchor based等一系列生成方法的发展,到18年开始,开始流行anchor free系列,CornerNe ...

  7. ESP32音频输入-MAX4466,MAX9814,SPH0645LM4H,INMP441(翻译)

    有几种方法可以将模拟音频数据输入到ESP32中. 直接从内置的模数转换器(ADC)读取 这对于一次性读取很有用,但不适用于高采样率. 使用I2S通过DMA读取内置ADC 适用于模拟麦克风,例如MAX4 ...

  8. DHCP工作原理

    DHCP:Dynamic Host Configurtion Protocol DHCP的工作原理(UDP) 1.客户端:首先会发送给一个dhcp discovery(广播)报文,报文中的2层和3层都 ...

  9. CF1225E题解 Rock Is Push

    在打CF的时候没想到www这个dp真的蛮巧妙的 这是一道dp题(废话 假设我们走到了\((i,j)\)位置,因为我们只能下移/右移,那么我们所有上方与左方的石块(即\(\{ (i,j)|i<n ...

  10. python 17篇 unittest单元测试框架

    单元测试:开发程序的人自己测试自己的代码 unittest自动化测试框架 1.单元测试 import unittest def add(a,b): return a+b # 在运行时不要用run un ...