Servlet学习

Servlet

Servlet简介

  • 开发动态web的一门技术
  • 作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层,即接收客户端发送过来的请求并且响应数据给客户端
  • Sun公司在API中提供了一个接口:Servlet; 开发Servlet程序只需要完成两个小步骤:
    • 编写一个类实现Servlet接口;
    • 把开发号的Javalei部署至web服务器中;

把实现了Servlet接口的Java程序叫做Servlet

配置Servlet

  1. 新建一个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>
    
  2. 新建一个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);
        }
    }
    
  3. 编写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

  4. 配置Tomcat

    检查这些选项:

    image-20210725145516261

Servlet原理

Servlet是由服务器调用, web服务器在收到浏览器请求后, 会:

image-20210725160307573

mapping相关注意点

  1. 一个Servlet请求可以指定一个映射路径

    <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/helloServlet</url-pattern>
        </servlet-mapping>
    
  2. 一个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>
    
  3. 一个Servlet请求可以指定通用映射路径

    <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/helloServlet/*</url-pattern>
        </servlet-mapping>
    
  4. 默认请求路径

    <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/*</url-pattern>
        </servlet-mapping>
    
  5. 可以自定义后缀实现请求映射

    <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>*.do</url-pattern>
        </servlet-mapping>
    <!-- *.do前不能加任何请求路径 -->
    
  6. 优先级问题

    指固有的映射路径优先级最高, 找不到则会走默认的处理请求(/*);

ServletContext

web容器在启动时, 会为每个web程序都创建一个对相应的ServletContext对象, 它代表了当前的web应用;

1.共享数据:

在一个Servlet中的数据可在另一个Servlet中拿到;

image-20210725164541099

  1. 创建一个放置数据的类

    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"
        }
    }
    
  2. 创建获取数据的类

    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);
        }
    }
    
  3. 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

image-20210725171442303

2.先输入createC再访问此地址

image-20210725171551419

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);
    }

image-20210725214407597

请求转发地址不变

4.读取资源文件

  1. 创建properties文件

    image-20210725221707248

  2. maven先执行clean, 再启动Tomcat, 找到target中的地址 (类路径)

    image-20210725221843550

  3. 编写类实现读取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);
        }
    }
    
  4. 添加映射

     <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>
    

运行结果

image-20210725222209647

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.常见应用

  1. 向浏览器输出消息

  2. 下载文件

    1. 获取下载文件的路径
  3. 确定下载的文件名

    1. 设置使浏览器能够下载我们需要的文件
  4. 获取下载文件的输入流

    1. 创建缓冲区
    2. 获取OutputStream对象
    3. FlieOutputStream流写入buffer缓冲区
    4. 使用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/hello
    • StringBuffer 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.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 用户登录界面简单实现

实现的功能:

  1. 含有登陆: 注册页面、其他页面。
  2. 登录功能:手动输入信息,符合已存在的用户信息则成功登录。
  3. 注册功能:手动输入信息,不能重复注册已存在的用户名,否则注册失败。
  4. 用户展示:在页面上展示所有已经注册的用户的信息。
  5. 登陆过滤:其他页面,只有登陆成功后才可访问,否则跳转至登陆页面。

图:

image-20210727000454077

image-20210727001003399

image-20210727000634254

运行测试:

  1. 启动Tomcat, 弹出网页

    image-20210726203756665

  2. 点击"用户信息", 会显示数据库中的所有用户名及密码

    image-20210726203912146

  3. 在"用户名"一栏中输入错误的用户名,点击"提交", 停在该页面并显示错误信息

    image-20210726204057842

  4. 输入正确的用户名, 但输入错误的密码,点击"提交"

    image-20210726204300337

  5. 输入正确的用户名及密码, 点击"提交":跳转到另一网页

    image-20210726205710566

  6. 输入已存在的用户名,点击"注册"

    image-20210726204844810

  7. 输入可用用户名和密码, 点击在"注册"

    image-20210726205934029

    image-20210726205918894

    再点击用户信息, 已经更新

    image-20210726210011988

    数据库中:

    image-20210726231355038

出现的问题:

  1. maven项目创建后没有自动生成.iml文件;

    解决:

    在Idea中的Terminal里输入命令:

    mvn idea:module

  2. Tomcat部署工件出错, 如图:

    image-20210725145105508

    解决:

    发现是地址中未以/开头, 补上即可正常运行;

    image-20210725144845685

  3. 运行tomcat服务器下,在项目中修改CSS文件,刷新页面不更新样式;

    解决:

    浏览器会缓存CSS\JS文件,在浏览器按F12打开开发者调试工具,点击右上角展开选项,选择settings,勾选图中选项,禁止缓存;

    image-20210725150138497

  4. JSP中一个表单中的两个按钮但分别执行两个action;

    解决:

    form标签中的action为空, 在submit标签中加入如下语句:

    image-20210726202427513

  5. 在catch语句中加入return语句方法不能退出;

    原因:在正常情况(即程序正常执行try catch finally语句块,不会在语句中出现退出程序、线程终止等特殊情况)下,都会执行finally语句块,如果finally中有return,则程序会走finally中的return,如果没有,则先执行try或者catch中的return,将其存入临时栈中,执行完finally语句后才返回临时栈中的值。
    解决:

    加入对应返回值的临时变量, 在catch中对其赋值;

  6. 如何在网页中回显后端传的值;

    解决:

    利用set\getAttribute实现:

    image-20210726203349734

    在jsp中(<% %>)

    image-20210726203416728

  7. HTTP404

    解决:

    url-pattern 大小写敏感

    image-20210726204739769

    image-20210726204831361


参考:

【集训】Servlet - Reria’s BLOG (miss-reria.github.io)

【狂神说Java】JavaWeb入门到实战_哔哩哔哩_bilibili

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值