ServletRequest

ServletRequest

其实就是对于请求报文的封装。Connector接收到请求报文之后会将请求报文解析成request对象,接下来,将request对象传给engine—host—Context(根据请求,判断有没有servlet可以处理该请求,如果有,则调用servlet,service方法(request,response);如果没有servlet可以处理该请求,那么回交给缺省servlet)

如果你希望获取请求报文里面的数据,那么从request里面取就可以了,如果你希望设置响应报文,那么只需要往response里面写入数据,然后Connector回读取response里面的内容。

还有一个对象,HttpServletRequest

我们之前说,客户端可以发送很多协议的请求,http协议、ajp协议等

http协议的请求报文和ajp协议的请求报文肯定有不同的地方,但是肯定也有相同的地方。

共性的地方是不是可以写在ServletRequest中,个性的部分写在每个协议的报文所对应的request中,其中http所特有的性质就应该出现再HttpServletRequest中。

但是对于一般情况下而言,我们99%场景下使用的都是浏览器去发送请求,浏览器发送的全部都是HTTP请求,所以你几乎可以将HttpServletRequest和ServletRequest做一个等号。

理应可以获取到请求报文的各个部分。

HTTP请求报文

请求行:请求方法 请求资源 版本协议

请求头

请求体

Pig

Dog

public void run(Animal animal){

​ animal.run();

}

debug

在这里插入图片描述

resume program按钮非常的重要

这个按钮的作用:

如果下面代码没有断点,那么回执行完全部代码;如果下面有代码,那么回跳转到下面的断点。

常用API

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

@WebServlet("/request1")
public class RequestServlet1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取HTTP请求报文的各个部分
        String method = request.getMethod();
        String requestURI = request.getRequestURI();
        String requestURL = request.getRequestURL().toString();
        String protocol = request.getProtocol();
        // requestURI  URL 要比URI长一些  访问协议,主机,端口号
//        System.out.println(method + " " + requestURI + " " + protocol);
//        System.out.println(method + " " + requestURL + " " + protocol);
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()){
            String headerName = headerNames.nextElement();
            String headerValue = request.getHeader(headerName);
            //System.out.println(headerName + ":" + headerValue);
        }
        //获取请求体的方法
        //ServletInputStream inputStream = request.getInputStream();
        String remoteAddr = request.getRemoteAddr();
        int remotePort = request.getRemotePort();
        String localAddr = request.getLocalAddr();
        int localPort = request.getLocalPort();
        System.out.println("客户机:" + remoteAddr + "端口号:" + remotePort + "访问了服务器:" + localAddr + "端口号:" + localPort);
    }
}

获取请求参数

对于request来说,最为核心的一个功能就是获取请求参数。请求参数是什么样的结构?

key=value&key=value型的数据

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;

@WebServlet("/submit")
public class SubmitServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //如何获取form表单提交的各种类型的请求参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        //如果提交的参数是checkbox,使用该方法可能获取的结果不全
        //String gender = request.getParameter("gender");
        String hobby = request.getParameter("hobby");
        String province = request.getParameter("province");
        String[] hobbies = request.getParameterValues("hobby");
        System.out.println(username);
        System.out.println(password);
        //System.out.println(gender);
        System.out.println(hobby);
        System.out.println(province);
        System.out.println(Arrays.toString(hobbies));
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

需要特别说明的一点:

该方法获取请求参数有一个注意事项,那么就是只可以获取到key=value&key=value型的数据,如果数据提交的数据结构不是该类型,那么无法获取到请求参数;同时该方法获取请求参数和使用get或者post请求方式无关,

封装数据

经常会需要将获取到的请求参数封装到一个对象中,如何封装数据到一个对象中呢?对象一般情况下我们称之为一个bean。

JavaBean

一个对象满足以下几点,我们一般就称之为一个JavaBean

1.成员变量设置为private,同时提供public的get和set方法

2.必须要有无参构造函数

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;

@WebServlet("/submit2")
public class SubmitServlet2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //如何获取form表单提交的各种类型的请求参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        //如果提交的参数是checkbox,使用该方法可能获取的结果不全
        String gender = request.getParameter("gender");
        //String hobby = request.getParameter("hobby");
        String province = request.getParameter("province");
        String[] hobbies = request.getParameterValues("hobby");
        User user = new User(username, password, gender, hobbies,province);
        System.out.println(user);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//        doPost(request, response);
    }
}

有一个问题:

如果前端页面提交的请求参数非常多,那么服务器的代码也需要写很多对应的获取请求参数的逻辑,非常的冗余。

页面提交的请求参数:

username=admin&password=xxxx&gender=male…

再一些专门的框架中或者工具类中,如果它可以将数据动态的封装到对象中,一般情况下,它是这么来封装的

比如提交的参数username=admin&password=xxxx

接下来,它会到你需要封装到对象中去找对应的set方法,即setUsername和setPassword方法

利用该方法将username和password提交的参数封装到对象中。

约定俗成使用的一个规则。其实也是java编程规范里面的。

https://mvnrepository.com/

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;

@WebServlet("/submit3")
public class SubmitServlet3 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //如何获取form表单提交的各种类型的请求参数
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()){
            String name = parameterNames.nextElement();
            String[] values = request.getParameterValues(name);
            if(values.length == 1){
                System.out.println(name + ":" + values[0]);
            }else {
                System.out.println(name + ":" + Arrays.toString(values));
            }
            if("username".equals(name)){
                //这样操作是可以的,但是会显得非常臃肿,不智能
            }
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

使用第三个的工具类来完成数据的封装。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AzJc5jj5-1616070112951)(ServletRequest.assets/image-20210226154700395.png)]

新建一个lib目录,然后导入下载的jar包,此时还需要再做一步,否则,接下来IDEA再帮我们编译java文件的时候,会找不到对应的jar包。add as library,相当于再IDEA里面注册该jar包。那么接下来IDEA编译java文件的时候就可以拿到当前jar包的路径

javac -classpath xxx xxxx.java

报错信息需要重视 非常重要

在这里插入图片描述

EE项目在运行时,如果出现了该错误,那么有且只有一个唯一性可能,那就是在运行的时候,tomcat在执行我们的servlet代码时,找不到对应的jar包。

但是现在的情况是我们servlet没有main方法,全凭tomcat调用。

会到应用/WEB-INF/classes目录下去加载你的class文件,会到应用/WEB-INF/lib目录下去加载依赖的jar包,所以,在别人的地盘,你得按照别人的规则来行事

硬盘上面的class文件一定要加载到内存中才可以,而这一步是由类加载器来完成的。

tomcat提供的类加载器再加载我们应用下面的class以及jar包的时候,它只会到WEB-INF/classes以及WEB-INF/lib目录下加载其他地方不会去加载,所以你放置文件一定要放置在这些位置。

import org.apache.commons.beanutils.BeanUtils;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

@WebServlet("/submit5")
public class SubmitServlet5 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        User user = new User();
        //使用一个第三方的工具类来完成数据的封装,工具类使用起来非常简单
        //BeanUtils---如何去下载jar包呢?
        //可以到官网去下载,或者到另外一个类库比较全的网站
        //会把第二个参数map里面的键值对封装到第一个参数的object中
        Map<String, String[]> parameterMap = request.getParameterMap();
        try {
            BeanUtils.populate(user, parameterMap);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        System.out.println(user);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

获取请求参数中文乱码

需要大家去记住一个API。

设置请求体里面的编码格式(如果请求行里面附带请求参数,该API不会生效。);该API必须要求在读取请求参数之前调用,否则无效;

void setCharacterEncoding(java.lang.String env)
                          throws java.io.UnsupportedEncodingException

Overrides the name of the character encoding used in the body of this request. This method must be called prior to reading request parameters or reading input using getReader().

  • Parameters:

    env - a String containing the name of the character encoding.

  • Throws:

    java.io.UnsupportedEncodingException - if this is not a valid encoding

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        usename=xxx&password=xxx&gender=xxx&....
        <form action="http://localhost:8080/app/submit5" method="post">
            <input type="text" name="username"><br>
            <input type="password" name="password"><br>
            <input type="radio" name="gender" value="male"><input type="radio" name="gender" value="female"><br>
            <input type="checkbox" name="hobby" value="java">java
            <input type="checkbox" name="hobby" value="python">python
            <input type="checkbox" name="hobby" value="c++">c++<br>
            <select name="province">
                <option value="wuhan">武汉</option>
                <option value="beijing">北京</option>
                <option value="shanghai">上海</option>
            </select>
            <input type="submit">
        </form>
    </body>
    </html>
    

    以post请求方式提交的

    
    import org.apache.commons.beanutils.BeanUtils;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.util.Map;
    
    @WebServlet("/submit5")
    public class SubmitServlet5 extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            User user = new User();
            //使用一个第三方的工具类来完成数据的封装,工具类使用起来非常简单
            //BeanUtils---如何去下载jar包呢?
            //可以到官网去下载,或者到另外一个类库比较全的网站
            //会把第二个参数map里面的键值对封装到第一个参数的object中
            request.setCharacterEncoding("utf-8");
            Map<String, String[]> parameterMap = request.getParameterMap();
            try {
                BeanUtils.populate(user, parameterMap);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            System.out.println(user);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request, response);
        }
    }
    

那如果以get请求方式提交参数呢?

请求参数如果在地址栏中,那么是没有乱码问题的(前端页面提交的请求参数编码格式为utf-8)

介绍几种常见的网络路径写法

1.全路径
http://localhost/app/servlet1

实际使用中使用的并不是特别的多。

介绍今后大家开发的过程中,遇到的几个环境

公司:

技术:

技术主管,CTO,架构的设计

​ 多个项目在并行—多个项目同时在研发。 Super Cell 中台

​ 每个项目由一个项目负责人 Team Leader

​ 每个项目组由如下成员:

项目经理(制定需求的)

UI 用户界面

前端开发 html页面----前端框架的崛起, js、css、html、 TypeScript

服务端开发-----java、c++、nodejs、go、python、c#

​ 大公司可能还会由DBA—数据库这块造诣很深

测试-提bug,有的公司KPI,测试的KPI看找到多少个bug,服务端绩效也是看被找到多少个bug

​ 安全性测试(蚂蚁绝对有,而是将安全测试交给专业的安全公司来做)

项目立项—公司的性质,自研产品,外包公司

​ 为什么要去开发这个软件,如何去开发,定位,社区团购

​ 需求评审—评估这些功能是否合理(根据手机壳颜色改主题颜色)、这些功能是否在一个版本内发布(先发布哪一个版本)

​ 社交软件

​ 需求文档

​ 代码开发----开发完毕,测试

开发环境、测试环境、生产环境

测试人员在测试代码的时候,是不会在你本机上测试的,会再一个局域网的环境里面测试。(因为测试的目的是把潜在的bug给找到出来,以免在生产环境中暴露问题,这个环境应当尽可能去复现生产环境,尽可能保持环境相同)

最后,并不是说全路径绝对不可以写,如果能够将这些可变的部分以配置文件的形式配置下来,还是可以写的

2.相对路径

访问的页面相对于当前页面的一个相对路径

比如当前页面:http://localhost/app/form.html

提交的路径为:http://localhost/app/submit

那么相对路径应该如何来写呢?

sumit

相对路径推荐吗?不是特别推荐,因为此时提交的路径会过分依赖于当前页面的路径,如果当前页面的路径发生变化,那么最终的提交路径也会跟着一起变。

3./开头的路径(推荐的写法)

/应用名/资源路径

实际上该路径的写法就是把全路径中访问协议、主机、端口号部分给去掉,不管当前页面的路径如何变化,那么提交的路径始终不需要发生变更。

/app/servlet1

/app/1.html

转发包含(了解)

目前为止,我们学习的都是关于一个servlet处理请求的,如果今后需要一个servlet处理完结果以后调用另外一个servelt或者一个servlet处理完结果以后调用一个页面,那么依靠目前学习的知识是无法完成的。更多的是关于组件和页面之间的交互。但是呢,目前使用java技术来解决页面的方案其实已经非常少了,java目前地位主要是给前端来提供数据,前端来负责页面的跳转。

前后端分离。

登录-------servlet来处理逻辑---------登录成功,显示个人页面

一个请求到来之后,交给一个servlet来处理,servlet处理完毕之后,需要将请求交给另外一个servlet,或者将请求交给另外一个页面来最后做出响应,那么这个时候就可以使用转发。

转发特点:

​ 一个组件(源组件)执行完毕之后,它将响应的主动权交给另外一个组件(目标组件),后续响应主要由另外一个组件(目标组件)来负责。这里面涉及到了一个主动权变更的过程。

​ 代码层面的体现:

针对源组件来说,转发前后,源组件可以在最终的响应报文中留下响应头,但是无法留下响应体。

包含其实主要用在页面包含另外一个页面中,最大的特征,主动权还在自己手中,源组件包含过后仍然可以设置响应体

转发:

servlet--------------> html(响应体)

包含:

html (响应体由该组件来提供)<------------------ html

需要特别注意一点的就是关于/开头的路径在

转发里面书写发现访问不到。

转发里面/开头的路径必须要求把应用名给去掉才可以正常访问。

为什么呢?应用部署再服务器里面,服务器知不知道你的应用名,所以tomcat服务器会自动帮我们加上应用名

但是你分析以下,浏览器知不知道你的应用名叫啥?/app/1.html

口诀:

记忆/开头路径时,从以下角度去记忆需不需要加应用名。

如果该路径的执行解析主体是服务器,那么就不需要加应用,直接/资源路径即可 转发

如果该路径的执行解析主体是浏览器,那么就需要加应用名,/应用名/资源路径,比如form action img src a href

实际的应用场景:

登录----------提交到一个servlet------跳转到成功、失败页面

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

念广隶

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

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

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

打赏作者

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

抵扣说明:

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

余额充值