文章目录
- HttpServletRequest概述
- request对象和response对象的原理
- request对象继承体系结构
- reques获取功能
- reques其他功能
- 路径写法
- 获取user-agent和referer请求头并演示兼容和盗链
- 案例:用户登录
- BeanUtils工具类,简化数据封装
HttpServletRequest概述
我们在创建Servlet时会覆盖service()方法,或doGet()/doPost(),这些方法都有两个参数,一个为代表请求的request和代表响应response。service方法中的request的类型是ServletRequest,而doGet/doPost方法的request的类型是HttpServletRequest,HttpServletRequest是ServletRequest的子接口,功能和方法更加强大的HttpServletRequest。
request对象和response对象的原理
1. request和response对象是由服务器创建的。我们来使用它们
2. request对象是来获取请求消息,response对象是来设置响应消息
request对象和response对象的运行流程
request对象继承体系结构
ServletRequest -- 接口
| 继承
HttpServletRequest -- 接口
| 实现
org.apache.catalina.connector.RequestFacade 类(tomcat)
reques获取功能
1.获取请求行数据
获取下面请求中的任意信息。
GET /ginger/request?name=zhangsan HTTP/1.1
@WebServlet("/request")
public class RequestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//http://localhost:8080/ginger/request
//1. 获取请求方式:GET
String method = req.getMethod();
//2. 获取虚拟目录:/ginger
String contextPath = req.getContextPath();
//3. 获取Servlet路径:/request
String servletPath = req.getServletPath();
//4. 获取get方式请求参数:name=zhangsan
String queryString = req.getQueryString();
//5. 获取请求URI:/ginger/request
String requestURI = req.getRequestURI();
//6. 获取请求URL:http://localhost:8080/ginger/request
StringBuffer requestURL = req.getRequestURL();
//7. 获取协议及版本:HTTP/1.1
String protocol = req.getProtocol();
//8. 获取客户机信息:
//0:0:0:0:0:0:0:1本机地址获取为了IPV6的IP,这现象只有在服务器和客户端都在同抄一台电脑上才会出现
String remoteHost = req.getRemoteHost();
String remoteUser = req.getRemoteUser();//null
//0:0:0:0:0:0:0:1本机地址获取为了IPV6的IP,这现象只有在服务器和客户端都在同抄一台电脑上才会出现
String remoteAddr = req.getRemoteAddr();
int remotePort = req.getRemotePort();//54244
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
}
2. 获取请求头数据
@WebServlet("/request2")
public class RequestServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过请求头的名称获取请求头的值:Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0
String header = req.getHeader("user-agent");
System.out.println(header);
//获取所有的请求头名称:
Enumeration<String> headerNames = req.getHeaderNames();
//Enumeration类似迭代器,遍历就行了。
while (headerNames.hasMoreElements()){
//获取所有请求头对应的信息。
System.out.println(req.getHeader(headerNames.nextElement()));
//获取的请求头信息
//localhost:8080
//Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0
//text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
//zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
//gzip, deflate
//keep-alive
//JSESSIONID=C91DCF88358233DFDACC8954C8120A0A
//1
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
3. 获取请求体数据
请求体:只有POST请求方式,才有请求体,在请求体中封装了POST请求的请求参数
步骤:
1. 获取流对象
BufferedReader getReader():获取字符输入流,只能操作字符数据
ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据
2. 再从流对象中拿数据
@WebServlet("/request3")
public class RequestServlet3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//步骤:
//1. 获取流对象
//BufferedReader getReader():获取字符输入流,只能操作字符数据
//BufferedReader reader = req.getReader();
//ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据
ServletInputStream inputStream = req.getInputStream();
//2. 再从流对象中拿数据
//字符流获取数据
/* String line= null;
while ((line=reader.readLine())!=null){
System.out.println(line);
}*/
System.out.println("-------------------------");
//字节流获取数据
byte[] bys= new byte[1024*8];
int len = 0;
while((len=inputStream.read(bys))!=-1){
System.out.println(new String(bys,0,len));//username=zhangsan&password=123456
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
reques其他功能
1. 获取请求参数通用方式:不论get还是post请求方式都可以使用下列方法来获取请求参数
中文乱码问题:
get方式:tomcat 8 已经将get方式乱码问题解决了
如果是tomcat低于8还是要解决乱码
String name = new String(name.getBytrs("ISO8859-1"),"UTF-8");
post方式:会乱码
解决:在获取参数前,设置request的编码request.setCharacterEncoding("utf-8");
@WebServlet("/request4")
public class RequestServlet4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//get提交方式
//1. String getParameter(String name):根据参数名称获取参数值
//结果:张三
String username = req.getParameter("username");
//2. String[] getParameterValues(String name):根据参数名称获取参数值的数组
//结果:疾风剑豪 影流之主
String[] hobbys = req.getParameterValues("hobby");
for (String hobby : hobbys) { System.out.println(hobby); }
//3. Enumeration<String> getParameterNames():获取所有请求的参数名称
//结果:host user-agent accept accept-language accept-encoding connection referer cookie upgrade-insecure-requests
Enumeration<String> headerNames = req.getHeaderNames();
//遍历获取到的参数名称数组
while (headerNames.hasMoreElements()) { System.out.println(headerNames.nextElement()); }
//4. Map<String,String[]> getParameterMap():获取所有参数的map集合。
//结果:username:张三 password:1234567 hobby:格雷福斯 疾风剑豪 影流之主
Map<String, String[]> parameterMap = req.getParameterMap();
//获取键值对对象集合并遍历
for (Map.Entry<String, String[]> me : parameterMap.entrySet()) {
String key = me.getKey();
String[] values = me.getValue();
System.out.print(key+":");
for (String value : values) {
System.out.print(value+" ");
}
System.out.println();
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
2. 请求转发:一种在服务器内部的资源跳转方式
请求转发图解
步骤:
1. 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
2. 使用RequestDispatcher对象来进行转发:forward(ServletRequest request, ServletResponse response)
特点:
1. 浏览器地址栏路径不发生变化
2. 只能转发到当前服务器内部资源中。
3. 转发是一次请求
@WebServlet("/request5")
public class RequestServlet5 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1. 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
//RequestDispatcher requestDispatcher = req.getRequestDispatcher("/request4");
//2. 使用RequestDispatcher对象来进行转发:forward(ServletRequest request, ServletResponse response)
//requestDispatcher.forward(req, resp);
//连式编程
req.getRequestDispatcher("/request4").forward(req,resp );
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
结果:
转发到了demo04........
3. 共享数据
域对象:一个有作用范围的对象,可以在范围内共享数据
request域:代表一次请求的范围,一般用于请求转发的多个资源*享数据
@WebServlet("/request6")
public class RequestServlet6 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1. void setAttribute(String name,Object obj):存储数据
req.setAttribute("11111","法外狂徒");
req.setAttribute("22222","影流之主" );
//3. void removeAttribute(String name):通过键移除键值对
req.removeAttribute("22222");
//转发到request5
req.getRequestDispatcher("/request5").forward(req,resp );
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
从reqeust6转发到request5
@WebServlet("/request5")
public class RequestServlet5 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//2. Object getAttitude(String name):通过键获取值
Object obj1 = req.getAttribute("11111");
Object obj2 = req.getAttribute("22222");
System.out.println(obj1);
System.out.println(obj2);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
结果
法外狂徒
null
4. 获取ServletContext
@WebServlet("/request7")
public class RequestServlet7 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取ServletContext两种方式
ServletContext servletContext = req.getServletContext();
ServletContext servletContext1 = this.getServletContext();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
路径写法
路径分类
- 相对路径:通过相对路径不可以确定唯一资源
如:./index.html
不以/开头,以.开头路径
规则:找到当前资源和目标资源之间的相对位置关系
./:当前目录
../:后退一级目录
- 绝对路径:通过绝对路径可以确定唯一资源
如:http://localhost:8080/ginger/response3 /ginger/response3
以/开头的路径
规则:判断定义的路径是给谁用的?判断请求将来从哪儿发出
给客户端浏览器使用:需要加虚拟目录(项目的访问路径)
建议虚拟目录动态获取:request.getContextPath()
<a> , <form> 重定向...
给服务器使用:不需要加虚拟目录
转发路径
相对路径和绝对路径一般都是通过需求来判断路径写法。
相对路径演示
定义一个html页面
<body>
<h3>相对路径就是当前资源路径相对于目标资源路径的相对位置关系</h3>
<p>
当前资源:localhost.html
http://localhost:8080/ginger/localhost.html
</p>
<p>
目标资源:/response3
http://localhost:8080/ginger/response3
</p>
<!--response3代表./response3-->
<a href="response3">response3</a><br>
<!--html/location2.html代表./html/location2.html-->
<a href="html/location2.html">location2.html</a>
</body>
并访问页面
点击response3
点击location2.html
绝对路径演示
重定向在response有演示
转发在上面有演示
获取user-agent和referer请求头并演示兼容和盗链
user-agent头应用演示
@WebServlet("/request8")
public class RequestServlet8 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//演示获取请求头数据:user-agent
String agent = req.getHeader("User-Agent");
if(agent.contains("Chrome")){
//谷歌
System.out.println("谷歌访问的......");
}else if(agent.contains("Firefox")){
//火狐
System.out.println("火狐访问的......");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
使用火狐访问结果:
火狐访问的......
referer头应用演示
假设这是腾讯平台
@WebServlet
public class RequestServlet9 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//演示获取请求头数据:referer表示该请求时从哪里来
String referer = req.getHeader("referer");
System.out.println(referer);
if(referer!=null){
//查看该访问连接中是否包含自己的项目路径。
if (referer.contains("/ginger")) {
//正常访问
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("播放电影....");
} else {
//盗链
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("想看电影吗?来腾讯吧...");
}
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
结果:我就是输出了一个该请求是从哪里来的
http://localhost/gaoqing/
假设创建新一个模块演示,表示其它的平台。(到时候会跳转到腾讯平台)
在该模块中写一个html页面用于访问腾讯平台
访问该页面
访问结果
案例:用户登录
画图分析:
我的项目结构
dao代码
public class UserDaoImpl {
private JdbcTemplate jt = new JdbcTemplate(JDBCUtils.getDaSource());
public User login(User user) {
try {
//定义sql语句
String sql = "select * from User where username=? and password=?";
User u = jt.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class),
user.getUsername(), user.getPassword());
return user;
} catch (DataAccessException e) {
return null;
}
}
}
pojo代码
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
servlet代码
@WebServlet("/failServlet")
public class FailServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("登录失败了,用户名或者密码错误。。。。");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取用户名和密码
//String username = req.getParameter("username");
//String password = req.getParameter("password");
//创建用户对象
//User user = new User();
//user.setUsername(username);
//user.setPassword(password);
//获取所有请求参数
Map<String, String[]> map = req.getParameterMap();
//使用BeanUtils简化封装
User user =new User();
try {
BeanUtils.populate(user,map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//调用dao方法
UserDaoImpl udi = new UserDaoImpl();
User u = udi.login(user);
//根据返回User对象是否为空,转发到成功或者失败页面。
if (u != null) {
req.setAttribute("user", u);
//转发到登录成功页面
req.getRequestDispatcher("/successServlet").forward(req, resp);
} else {
//转发到登录失败页面
req.getRequestDispatcher("/failServlet").forward(req, resp);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
@WebServlet("/successServlet")
public class SuccessServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
User user = (User)req.getAttribute("user");
//防止中文乱码
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("尊敬的"+user.getUsername()+"恭喜你登录成功!!!!!");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
test代码
public class UserDaoTest {
@Test
public void userDaoTest() {
JdbcTemplate jt = new JdbcTemplate(JDBCUtils.getDaSource());
User user = new User();
user.setUsername("ginger");
user.setPassword("123456");
//定义sql语句
String sql = "select * from User where username=? and password=?";
User u = jt.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class),
user.getUsername(), user.getPassword());
System.out.println(u);
}
}
utils代码
public class JDBCUtils {
private static DataSource ds;
//静态代码块用于初始化数据
static{
try {
//1.加载配置文件
Properties pro = new Properties();
//使用ClassLoader加载配置文件,获取字节输入流
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//2.初始化连接池对象
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static DataSource getDaSource() {
return ds;
}
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
}
druid.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///mydatabases
username=root
password=root
initialSize=5
maxActive=10
maxWait=3000
html页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--login.html中form表单的action路径的写法-->
<!--虚拟目录+Servlet的资源路径-->
<form action="/login/loginServlet">
用户名:<input type="text" placeholder="请输入用户名" name="username"><br>
密码:<input type="password" placeholder="请输入密码" name="password"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
代码测试
访问页面正确输入用户名和密码
转发到登录成功页面
访问页面错误输入用户名和密码
转发到登录失败页面
BeanUtils工具类,简化数据封装
用于封装JavaBean的
1. JavaBean:标准的Java类
1. 要求:
1. 类必须被public修饰
2. 必须提供空参的构造器
3. 成员变量必须使用private修饰
4. 提供公共setter和getter方法
2. 功能:封装数据
2. 概念:
成员变量:不是属性
属性:setter和getter方法截取后的产物
例如:getUsername() --> Username--> username
3. 方法:
1. setProperty()
2. getProperty()
3. populate(Object obj , Map map):将map集合的键值对信息,封装到对应的JavaBean对象中
证明成员变量不是属性
public class PropertyTest {
@Test
public void propertyTest() throws InvocationTargetException, IllegalAccessException {
User user = new User();
//假设成员变量就是属性
//根据属性设置值
BeanUtils.setProperty(user,"age" ,18);
System.out.println(user);//User{age=0}通过结果看出来成员变量不是属性
//证明截取settr和gettr是属性
//根据属性设置值
BeanUtils.setProperty(user,"hahaha" ,20 );
System.out.println(user);//User{age=20}通过结果看出来截取调用settr和gettr才是属性。
}
}
User类
public class User {
private int age;
//一般情况下都是setAget,下面写法想证明成员变量不是属性。
public void setHahaha(int age){
this.age = age;
}
//一般情况下都是getAget,下面写法想证明成员变量不是属性。
public int getHahaha(){
return age;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
'}';
}
}