Servlet入门

1、Servlet简介

Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。

狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。

2、HelloServlet

1.构建一个Maven项目。删掉里面的src目录,以后我们就在这个项目里建moudel,这个空的工程就是Maven主工程。

2.关于Maven父子工程的理解:

父项目会有:

<modules>
    <module>servlet-01</module>
</modules>

子项目会有:

<parent>
    <artifactId>javaweb-02-servlet</artifactId>
    <groupId>com.wsn</groupId>
    <version>1.0-SNAPSHOT</version>
</parent>

父项目的jar包子项目可以直接使用。

3.Maven环境优化:

  1. 修改web.xml为最新的。
  2. 将maven的结构搭建完整

4.编写一个servlet

  1. 编写一个普通类
  2. 实现Servlet接口,这里我们直接继承HttpServlet
public class HelloServlet extends HttpServlet {
 //由于get或者post只是请求实现的不同的方式,里面的代码都长得一样,所以节省空间,我们可以让他们互相调用,业务逻辑都一样
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter writer = resp.getWriter();//响应流
        writer.print("HelloServlet");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

5.编写Servlet的映射

为什么需要映射:我们写的是java程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务中注册我们写的servlet,还需要给他一个浏览器能访问的路径。

<!--注册servlet-->
<servlet>
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>com.wsn.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet的映射(请求路径)-->
<servlet-mapping>
    <servlet-name>HelloServlet</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>

6.配置Tomcat

7.启动测试

3、Servlet原理

Servlet是由wen服务器调用,web

4、Mapping问题

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

    <!--注册servlet-->
    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.wsn.servlet.HelloServlet</servlet-class>
    </servlet>
    <!--指定一个映射路径,只能通过localhost:8080/wsn/hello访问-->
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    
  2. 一个Servlet可以指定多个映射路径

    <!--注册servlet-->
    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.wsn.servlet.HelloServlet</servlet-class>
    </servlet>
    <!--指定多个映射路径,可以通过
    localhost:8080/wsn/hello
    localhost:8080/wsn/hello1
    localhost:8080/wsn/hello2
    localhost:8080/wsn/hello3访问
    -->
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello1</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello2</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello3</url-pattern>
    </servlet-mapping>
    
  3. 一个Servlet可以指定通用映射路径

    <!--注册servlet-->
    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.wsn.servlet.HelloServlet</servlet-class>
    </servlet>
    <!--指定通用映射路径,可以通过localhost:8080/wsn/hello本身和/任何字符
    localhost:8080/wsn/hello
    localhost:8080/wsn/hello/sadsadasdas
    localhost:8080/wsn/hello/wrqwr
    localhost:8080/wsn/hello/21312dsad访问
    -->
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello/*</url-pattern>
    </servlet-mapping>
    
  4. 指定默认路径(不建议使用)

    <!--注册servlet-->
    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.wsn.servlet.HelloServlet</servlet-class>
    </servlet>
    <!--指定默认路径,localhost:8080/wsn不会走首页而是走这个servlet,会把首页干掉,不要这样写-->
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    
  5. 可以自定义后缀映射路径

    <!--注册servlet-->
    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.wsn.servlet.HelloServlet</servlet-class>
    </servlet>
    <!--指定自定义后缀映射路径,通过
    localhost:8080/wsn/dasdasdsas.wangshaonan
    localhost:8080/wsn/sadas.wangshaonan
    localhost:8080/wsn/sda231.wangshaonan
    localhost:8080/wsn/fasd3213asda.wangshaonan访问
    -->
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>*.wangshaonan</url-pattern><!--注意这里*前面不能加任何映射路径-->
    </servlet-mapping>
    

优先级问题:

指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求,也就是/*的映射

例子:自定义404的映射

//创建一个ErrorServlet响应自定义的404
public class ErrorServlet extends HttpServlet {
    //重写doGet,doPost方法
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setCharacterEncoding("utf-8");//设置字符集
        resp.setContentType("text/html");//响应类型为text/html

        PrintWriter writer = resp.getWriter();//响应输出流
        writer.print("<h1>404</h1>");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);//相互调用
    }
}

xml映射

<!--注册servlet-->
<servlet>
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>com.wsn.servlet.HelloServlet</servlet-class>
</servlet>
<!--注册errorServlet(404)-->
<servlet>
    <servlet-name>errorServlet</servlet-name>
    <servlet-class>com.wsn.servlet.ErrorServlet</servlet-class>
</servlet>
<!--servlet的映射-->
<servlet-mapping>
    <servlet-name>HelloServlet</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>
<!--404的映射-->
<servlet-mapping>
    <servlet-name>errorServlet</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>
//结果:运行后,走localhost:8080/wsn/hello是可以进我们映射的指定页面,除此之外的任何地址都会跳转到我们自定义的404的页面,实现自定义的404页面。其实利用的就是‘固有的映射路径优先级最高’,其余的没设置的都走我们设定好的映射。

5、ServletContext(了解学习)

这一节下面的方法后面学习都会干掉,这里仅作为了解学习

web容器在启动的时候,为每个web程序都创建一个对应ServletContext对象,他代表了当前的web应用,凌驾于所有Servlet之上。

5.1、共享数据

共享数据:我在这个Servlet中保存的数据,可以在另外一个Servlet中拿到。

假设有三个Servlet实现类,各自都有对应的映射互不影响,那么怎么做能让他们之间的数据共享呢,在认识ServletContext之前我们能想到的方式就是用IO操作,例如servlet1将数据用输出流保存在一个文件(中介)中,然后servlet2要用的时候就用输入流读取这个文件中的内容实现数据传输。

显然这种方式效率太低,所以我们可以用ServletContext去实现Servlet之间的数据共享。

具体操作:

1.首先我们需要创建一个放置数据的类

public class HellowServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //this.getServletContext();   Servlet上下文
        String username = "wangshaonan";//数据
        ServletContext context = this.getServletContext();//创建一个上下文context容器
        //将一个数据以键值对的形式保存在SrevletContext中
        context.setAttribute("username",username);//第一个参数是key,第二个参数是value
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

2.然后创建一个取出数据的类

public class GetServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html");
        resp.setCharacterEncoding("utf-8");
        //读取HelloServlet中存在SrevletContext中的数据
        //创建上下文ServletContext对象
        ServletContext context = this.getServletContext();
        //context.getAttribute(key)通过key获得value
        String username = (String) context.getAttribute("username");
        //创建响应输出流对象
        PrintWriter writer = resp.getWriter();
        //将刚才get的数据打印在网页上
        writer.print("名字是"+username);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

3.配置注册和映射

<!--  hellowServlet注册  -->
<servlet>
    <servlet-name>helloServlet</servlet-name>
    <servlet-class>com.wsn.servlet.HellowServlet</servlet-class>
</servlet>
<!--  getServlet注册  -->
<servlet>
    <servlet-name>getServlet</servlet-name>
    <servlet-class>com.wsn.servlet.GetServlet</servlet-class>
</servlet>
<!--  hellowServlet映射  -->
<servlet-mapping>
    <servlet-name>helloServlet</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>
<!--  getServlet映射  -->
<servlet-mapping>
    <servlet-name>getServlet</servlet-name>
    <url-pattern>/get</url-pattern>
</servlet-mapping>

4.运行

当我们运行http://localhost:8080/wsn/get时发现我们存的数据是取不到的。

然后我们试着先运行存数据的页面http://localhost:8080/wsn/hello后再运行http://localhost:8080/wsn/get发现值正常取到了。

5.结论:ServletContext可以实现Servlet之间的数据共享,之间是存在先存后取的逻辑关系。

5.2、获得初始化参数

1.举例我们在web.xml里配置了jbdc连接数据库的初始化参数。

<!-- 设置初始化jdbc的url参数-->
<context-param>
    <param-name>jdbcUrl</param-name>
    <param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>

2.在ServletDemo03中用getInitParameter(String str)去获取初始化的那条参数。

public class ServletDemo03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获得getServletContext()上下文
        ServletContext context = this.getServletContext();
        //getInitParameter(str)通过键(Str key)获取 一条 初始化参数。
        String jdbcUrl = context.getInitParameter("jdbcUrl");
        //将他响应在网页上方便看效果:
        PrintWriter writer = resp.getWriter();
        writer.print(jdbcUrl);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

3.注册映射ServletDemo03

<!--ServletDemo03注册 -->
<servlet>
    <servlet-name>ServletDemo03</servlet-name>
    <servlet-class>com.wsn.servlet.ServletDemo03</servlet-class>
</servlet>
<!--ServletDemo03注册 -->
<servlet-mapping>
    <servlet-name>ServletDemo03</servlet-name>
    <url-pattern>/sp</url-pattern>
</servlet-mapping>

4.运行,获取成功

5.3、请求转发

1.编写转发的ServletDemo04类

public class ServletDemo04 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        //getRequestDispatcher(String url)转发的请求路径,参数里面是转发的映射路径
        RequestDispatcher requestDispatcher = context.getRequestDispatcher("/sp");
        requestDispatcher.forward(req,resp);//上面那个只是设置了路径,只有执行forward(req,resp)才是转发,参数对应请求和响应的参数。
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

2.注册映射ServletDemo04类

<!--ServletDemo04注册 -->
<servlet>
    <servlet-name>ServletDemo04</servlet-name>
    <servlet-class>com.wsn.servlet.ServletDemo04</servlet-class>
</servlet>
<!--ServletDemo04映射 -->
<servlet-mapping>
    <servlet-name>ServletDemo04</servlet-name>
    <url-pattern>/zf</url-pattern>
</servlet-mapping>

3.运行,发现我们访问http://localhost:8080/wsn/zf时展示的页面是http://localhost:8080/wsn/sp的页面,实现了转发。

5.4、读取资源文件

5.4.1、配置资源位置问题

properties类:

  • 在java目录下新建propereties。
  • 在resource目录下新建properties。

发现:

1.在java目录下新建propereties的文件运行后无法正常打包,而在resource目录下新建properties的文件会打包。因为resource目录下的文件会被默认打包,而java目录下的properties不会被打包,解决办法在之前Maven中讲到过,需要在pom.xml文件中加入两段配置代码。

<build>
    <resources>
        <resource><!-- 允许resource下的文件都被打包,也可以不写,默认就会打包 -->
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
        <resource><!-- 允许java下的文件都被打包 -->
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

配置完之后再次运行两个地方的资源都会被正常的打包。

2.发现java和resource下的资源都被打包在了同一路径下:classes,我们俗称这个路径为calsspath(类路径)。

5.4.2、读取资源

思路:主要就是怎么样把资源文件变成流。getResourceAsStream()

1.在resource文件夹下新建一个db.properties配置文件

username=root
password=123456

2.编写获取资源的ServletDemo05的类

public class ServletDemo05 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();//获取上下文对象(只要是获得资源都用这个)
        InputStream is = context.getResourceAsStream("/WEB-INF/classes/db.properties");//获取资源变成一个流对象,传入的参数是资源路径的字符串。
        //现在我们将获取的资源变成一个流,我们就可以使用properties对象去读取资源
        Properties prop = new Properties();//获取Properties对象
        prop.load(is);//加载资源,传入的是一个流对象
        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);
    }
}

3.注册映射ServletDemo05

<!--servletDemo05注册 -->
<servlet>
    <servlet-name>servletDemo05</servlet-name>
    <servlet-class>com.wsn.servlet.ServletDemo05</servlet-class>
</servlet>
<!--servletDemo05映射-->
<servlet-mapping>
    <servlet-name>servletDemo05</servlet-name>
    <url-pattern>/s5</url-pattern>
</servlet-mapping>

4.运行,发现资源正常得到读取展示。

6、HttpServletResponse

web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest对象和代表响应的一个HttpServletResponse对象。

  • 如果要获取客户端请求过来的参数:找HttpServletRequest
  • 如果要给客户端响应过去一些信息:找HttpServletResponse

6.1、简单将方法分个类(源码)

负责像浏览器发送数据的方法

//ServletResponse源码的方法
ServletOutputStream getOutputStream() throws IOException;//输出字节流
PrintWriter getWriter() throws IOException;//输出字符流

负责向浏览器发送一些请求头的方法(举例:设置编码和字符集)

//ServletResponse源码的方法
void setCharacterEncoding(String var1);
void setContentLength(int var1);
void setContentLengthLong(long var1);
void setContentType(String var1);
//HttpServletResponse源码的方法
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);

设置状态码的常量

//HttpServletResponse源码的常量
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.2、实现下载文件

  • 下载文件,我们平时在浏览器下载一些资源时,点击下载 就会跳转到一个页面,然后开始下载,就是用这个实现的。

    1. 获取下载文件的路径。
    2. 获取下载文件的文件名。
    3. 设置想办法让浏览器能够支持下载我们需要的东西。
    4. 获取下载的输入流。
    5. 创建缓冲区(Buffered)
    6. 获取OutputStream对象
    7. 将FileOutputStream流写入到buffer缓冲区。
    8. 使用OutputStream将缓冲区的数据输出到客户端。
public class FileServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1. 获取下载文件的路径。
        //通过上下文的getRealPath获取绝对路径
        String realPath ="E:\\Study\\java\\javaweb-02-servlet\\httpresponse\\src\\main\\resources\\liuchang.jpg";
        System.out.println("下载文件的路径:"+realPath);
        //2. 获取下载文件的文件名。
        //通过字符串的substring方法截取最后一个\符号的后面一个
        String fileName = realPath.substring(realPath.lastIndexOf("\\")+1);
        //3. 设置想办法让浏览器能够支持(Content-Disposition)下载我们需要的东西。中文文件名用URLEncoder.encode编码,否则会乱码
        resp.setHeader("Content-Disposition","attachment;filename"+ URLEncoder.encode(fileName,"utf-8"));
        //4. 获取下载的输入流。
        FileInputStream fis = new FileInputStream(realPath);//把文件变成流
        //5. 创建缓冲区(Buffered)
        byte[] buffer = new byte[1024];
        int length = 0;
        //6. 获取OutputStream对象
        ServletOutputStream ops = resp.getOutputStream();
        //7. 将FileOutputStream流写入到buffer缓冲区。使用OutputStream将缓冲区的数据输出到客户端。
        while ((length=fis.read(buffer))>0){
            ops.write(buffer,0,length);
        }
        fis.close();
        ops.close();
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

6.3、验证码功能

public class ImageServlet 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.pink);
        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("Prama","no-cache");
        //把图片写给浏览器
        ImageIO.write(image, "jpg", resp.getOutputStream());
    }
    //生成随机数的方法
    private String makeNum(){
        Random random = new Random();
        String str = random.nextInt(9999999)+"";//八位数
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 7-str.length(); i++) {
            sb.append("0");
        }
        String num=sb.toString()+str;
        return num;
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

6.4、重定向(需掌握)

一个web资源B收到客户端A的请求后,他会通知客户端A去访问另外一个web资源C,这个过程叫重定向。

常见使用场景:

  • 用户登录
void sendRedirect(String var1) throws IOException;

测试代码:

public class RedirectServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /*
        原理其实就是:
        resp.setHeader("location","/wsn/img")
        resp.setStatus(302);
        */
        resp.sendRedirect("/wsn/img");//sendRedirect重定向,当web访问这个servlet时,会跳转到/wsn/img
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

运行后red后跳转到img。

面试题:请你聊一聊重定向和转发的区别?

相同点:

  • 页面都会实现跳转。

不同点:

  • 请求转发的时候,url不会发生变化。
  • 重定向的时候,url地址栏会发生变化。

6.5、重定向表单测试(需掌握)

1.将首页index.jsp设置一个简单的登录表单,当点击提交时实现重定向跳转到success.jsp,这里注意action提交的路径问题。

<html>
    <body>
        <h2>Hello World!</h2>
        <%--这里提交的路径需要寻找到项目路径--%>
        <%--${pageContext.request.contextPath}代表当前项目路径--%>
        <form action="${pageContext.request.contextPath}/login" method="get">
            <span>用户名:</span>
            <input type="text" name="username"><br>
            <span>密码:</span>
            <input type="password" name="password"><br>
            <input type="submit">
        </form>
    </body>
</html>

2.写一个简单的success.jsp,作为提交成功的展示页面

<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <h1>Success</h1>
    </body>
</html>

3.编写重定向的RequestServlet

public class RequestTest extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //处理请求
        String user = req.getParameter("username");//获取用户名
        String pwd = req.getParameter("password");//获取密码
        System.out.println(user+":"+pwd);//输出到控制台
        //重定向注意路径问题。否则404
        resp.sendRedirect("/wsn/success.jsp");//处理完成,重定向至success.jsp
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

7、HttpServletRequest

HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器,Http请求中的所有信息会被封装到HttpServletRequest,通过这个HttpServletRequest的方法,我们可以获取到客户端的所有信息。

7.1、获取参数,并请求转发

public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置请求编码
        req.setCharacterEncoding("utf-8");
        //获取表单数据
        String user = req.getParameter("username");//获取用户名
        String pwd = req.getParameter("password");//获取密码
        String[] checkval = req.getParameterValues("hobbys");//获取checkbox的数据
        //输出到控制台
        System.out.println("==============================================================");
        System.out.println("用户名:"+user);
        System.out.println("密码:"+pwd);
        System.out.println(Arrays.toString(checkval));
        System.out.println("==============================================================");
        resp.setCharacterEncoding("utf-8");
        //通过请求转发
        req.getRequestDispatcher(req.getContextPath()+"/success.jsp").forward(req,resp);
//   	//重定向转发
// 		resp.sendRedirect(req.getContextPath()+"/success.jsp");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

面试题:请你聊一聊重定向和转发的区别?

相同点:

  • 页面都会实现跳转。

不同点:

  • 请求转发的时候,url不会发生变化。状态码:307
  • 重定向的时候,url地址栏会发生变化。状态码:302

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

echo wsn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值