该博客主要记录在学习黑马程序员Javaweb过程的一些笔记,方便复习以及加强记忆
🍡系列文章🍡
🚀🚀🚀
🍕 ✨JavaWeb学习笔记01BS架构 Maven Tomcat Servlet
🍔 ✨JavaWeb学习笔记02
request和response
🍟 ✨JavaWeb学习笔记03
JSP MVC
🌭 ✨JavaWeb学习笔记04待完善
一、request和response简介
这章我们学习request和response
request和response都是servlet中service方法的参数
即下图中的req和res
1.1 request和response有什么作用呢?
request装着浏览器根据http协议发来的请求数据
浏览器会发送请求数据给服务器,tomcat会把请求数据放到request对象中保存
我们可以使用request来获取请求数据
相应的,tomcat会发送相应数据给浏览器,我们可以在response对象来设置相应数据
二、request
先由一个小案例开始讲起:
实现一个互动:登录某个平台,登录进去后显示xxx欢迎您的字样
做法是用request去获取某个请求数据,然后可以通过response去相应到网页上
如下图:注意图二中链接带有请求数据name=lisi
这里的运行原理如下图
【浏览器发送请求,servlet中的方法的request参数处理,通过第二个参数(即response)相应数据】
由于httpservlet是servlet的实现类,所以httpservlet也有参数request和response 下面我们以httpServlet为例,来讲解servlet接口的使用
2.1 request获取请求数据的方法
request获取请求数据的方法【请求方法是get的情况(get方法请求请求参数是在请求行)】
如果是post的话就需要获取请求体,下图第三点:
// 获取请求方式:get
String method = req.getMethod();
System.out.println(method);
//获取虚拟目录
String contextPath = req.getContextPath();
System.out.println(contextPath);
//获取url,统一资源定位符号
StringBuffer url = req.getRequestURL();
System.out.println(url.toString());
//获取uri
String uri = req.getRequestURI();
System.out.println(uri);
//获取请求参数,get方式的 如username = lisi,post的请求参数在请求体中,要在dopost中用字符输入流获取
String queryString = req.getQueryString();
System.out.println(queryString);
运行结果【当我本地输入 http://localhost:8080/web002_war/d1?username=lisi之后】
如果是post请求的话,需要这样子获取请求数据
2.2 request通用方式获取请求参数
获取请求数据之后【仅此是get,post的请求获取请求数据方式不一样】doget方法和dopost方法都会执行一样的数据处理代码,无疑会带来代码的重复
然而request已经封装好了一些方法,req中里面会自己判断是get还是post同时提供方法直接让你获取键值对
get方式和post方式是两个方法,代码逻辑都一样【只有获取请求参数的代码不一样】,为了方便开发【防止代码写两份】要在dopost中写入
this.doGet(req,rep);
然后在doget中完善逻辑【处理获取到的请求数据】
2.3 案例
创建一个表单,然后使运用req的方法把键值对取出来
html代码如下
<form action="/web001/d2" method="get">
<input type="text" name="username"><br>
<input type="password" name="password"><br>
<input type="checkbox" name="hobby" value="1"> 游泳
<input type="checkbox" name="hobby" value="2"> 跑步 <br>
<input type="submit">
</form>
效果如下图
因为使用get方式进行表单的提交,提交后浏览器地址为【注意后面带的请求参数】
http://localhost:8080/web002_war/d2?username=zhangsan&password=123123&hobby=1&hobby=2
doget中request的方法
Map<String,String[]> map= req.getParameterMap();
for(String key : map.keySet())
{
//所有键
System.out.print(key+" : ");
//获取值的数组
String[] values = map.get(key);
for(String value:values)
{
System.out.print(value+" ");
}
System.out.println();
}
System.out.println("-------------");
//根据key获取参数值数组
String[] hobbies = req.getParameterValues("hobby");
for(String h : hobbies)
{
System.out.println(h);
}
System.out.println("---------------");
//根据key获取单个参数值
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username+password);
控制台输出
现在我们可以直接使用Request的通用方法去获取请求参数,比之前的处理方便了不少
代码模板如下,我们可以直接使用idea去快速创建
一般情况我们可以在新建中找到新建Servlet,如果没有就按下面步骤设置,根源选中路径最后为Java的那个
idea中还可以修改servlet的模板,如下图
2.4 乱码问题以及解决方法
在1上面表单中,假如账号【请求参数】中输入中文,在控制台会输出乱码。
为什么会出现乱码呢?如何解决
如下图右:浏览器以UTF-8的方式编码发送给服务器,服务器以ISO的形式去解码,固然会出现乱码
解决方法:要把iso解的码转换为字节码,再用字节码转utf8
如解决上面username的方法
username = new String(username.getBytes(StandardCharsets.ISO_8859_1),"UTF-8"); //tomcat7中文乱码解决方案
如果我们配置的tomcat版本是8以及以上的就不用担心乱码问题
如果仍然出现问号以及乱码可以参考【这篇文章】
出现问号尝试在tomcat配置中虚拟机选项【vm options】加入
-Dfile.encoding=UTF-8
2.5 请求转发概念
请求转发是什么?
浏览器只是一次请求,但是服务器之间跳转不只一次,可以服务器跳转中共享数据
如何请求转发? 如何在请求转发之间共享数据?
参考下面代码:
我们创建两个servlet,分别设置路径为 /d4 和 /d5
@WebServlet(value = "/d4")
public class ServletDemo4 extends HttpServlet {
// 请求转发
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("d4...");
//设置转发的数据【键值对】
request.setAttribute("nba","cba");
request.getRequestDispatcher("/d5").forward(request,response);
}
@WebServlet(value = "/d5")
public class ServletDemo5 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("d5...");
// 根据键获取转发来的数据
Object nba = request.getAttribute("nba");
System.out.println(nba);
// 删除转发的数据
System.out.println("现在删除nba这个键对应的键值对");
request.removeAttribute("nba");
}
当浏览器访问d4资源的时候服务器会先进入d4执行d4代码 然后跳转到d5中
浏览器会输出
d4...
d5...
现在删除nba这个键对应的键值对
cba
null
三、response
3.1 response的方法以及如何做出相应
如何响应数据:我们可以利用response获取字符输出流,然后调用write方法往网页中写入HTML代码
3.2 重定向 以及与请求转发的区别
上图得知,response可以设置响应行和响应头,可以做到重定向
重定向:浏览器发送来的请求a资源做不到,只好给个b资源地址让浏览器再发送一次请求
注意:重定向浏览器地址栏路径会发生变化,而请求转发不会,如上面例子浏览器地址栏路径一直是d4,不会变成d5
代码如下:
response.setStatus(302);
response.setHeader("location","/web002_war/r2");
便捷写法:
response.sendRedirect("/web002_war/r2");
降低耦合性【最终写法】:
String contextPath = request.getContextPath(); //获取虚拟目录
response.sendRedirect(contextPath+"/r2");
3.3 什么时候要加虚拟目录
上面例子中,可以发现请求转发是的路径不用加虚拟目录而重定向需要加虚拟目录
那什么时候加与不加呢?
如上图:重定向是给浏览器去重定向的,就不需要加虚拟目录。
3.4 修改虚拟目录
当然虚拟目录也是可以修改的
这里可以参考文章 idea中修改虚拟目录
3.5 response相应字符数据
使用如下:
3.6 response相应字节数据
使用如下:字节数据一般是为了输出图片视频等
四、案例【用户登录和用户注册】
使用以上知识在网页实现用户登录以及用户注册功能
4.1 用户登录流程
mybatis官网 链接
这里提供简单的静态页面代码
<form action="/web002_war/loginServlet" method="post">
账户 <input type="text" name="username"> <br>
密码 <input type="password" name="password"> <br>
<input type="submit" value="login ">
</form>
mybatis-config.xml代码,这个可以到官网查看
下面的 useSSL=false&allowPublicKeyRetrieval=true 为关闭安全连接,不加上有时候会报错
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 起别名-->
<!-- <typeAliases>-->
<!-- <package name="com.pojo"/>-->
<!-- </typeAliases>-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///web?useSSL=false&allowPublicKeyRetrieval=true"/>
<property name="username" value="root"/>
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<mappers>
<!-- <mapper resource="org/mybatis/example/BlogMapper.xml"/>-->
<!-- 包扫描-->
<package name="com.mapper"/>
</mappers>
</configuration>
UserMapper.xml【映射文件】代码,也是可以到官网中找到的
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mapper.UserMapper">
</mapper>
usermapper代码
loginServlet代码
@WebServlet(value = "/loginServlet")
public class loginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
// 接收用户名密码
String username = req.getParameter("username");
String password = req.getParameter("password");
//调用mybatis完成查询
// 获取sqlSessionFactory对象
String resource = "mybatis-config.xml";//这里记得修改,mybatis官网中可以找到这段代码
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取mapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 调用方法查找
user se = mapper.select(username, password);
// 释放资源
sqlSession.close();
PrintWriter writer = res.getWriter();
// 假如查询不为空,即数据库中有对应的name和password
if(se!=null)
{
writer.write("yes");
}else{
writer.write("no");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
this.doGet(req, res);
}
}
4.2 用户注册
用户注册和用户登录差别不大,只是添加一些方法和数据处理代码
在usermapper接口中增加代码
第一个方法是验证用户名是否已经被注册,第二个方法是增加账户和密码到数据库中
@Select("select * from user where name = #{name}")
user select2(@Param("name")String name);
@Insert("insert into user values (null,#{name},#{password}) ")
void add(user u);
对应的regisServlet代码,记得提交事务
@WebServlet(value = "/regisServlet")
public class regisServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
user u1 = new user();
u1.setName(username);
u1.setPassword(password);
// 获取sqlSessionFactory对象
String resource = "mybatis-config.xml";//这里记得修改,mybatis官网中可以找到这段代码
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取mapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 调用方法查找
user se = mapper.select2(username);
res.setCharacterEncoding("UTF-8");
PrintWriter writer = res.getWriter();
res.setContentType("text/html;charset=utf-8"); //修改编码
if(se==null)
{
mapper.add(u1);
sqlSession.commit();
// 释放资源
sqlSession.close();
}else{
writer.write("<h1>注册失败</h1>");
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/web002_war/regisServlet" method="post">
<p>账户 <input type="text" name="username"> <br></p>
<p>密码 <input type="password" name="password"> <br></p>
<input type="submit" value="login ">
</form>
<p>已有账号?</p><p><a href="login.html">登录</a></p>
</body>
</html>
4.3 大体步骤、文件结构、注意事项
文件结构:
步骤
先配置好mybatis环境:
1. 创建核心配置文件,官网中找代码
2. 创建usermapper类,同时在resources文件夹中创建映射文件【创建文件夹是分隔符用"/“而不是”."】
3. 创建实体类【创建get、set和构造方法】,放在pojo文件夹中,实体类user对应的是用户的账号密码
编写前端页面代码:
配置tomcat:
写servlet类:
注意
创建servlet类之前需要先在idae中配置好tomcat !!!
创建servlet类之前需要先在idae中配置好tomcat !!!
创建servlet类之前需要先在idae中配置好tomcat !!!
否则servlet部分功能是不全的,而且在pom.xml配置文件中导入servlet最好是2.5以及以上版本
jdk建议1.8,有时候版本18是无法运行的
4.4 代码优化
在上述代码中,我们会发现loginservlet和regisservlet创建工厂的代码重复了,我们可以构造一个工具类来专门创建工厂,从而进行优化的目的
先了解一个知识点:
静态代码块会随着类的加载而自动执行,且只执行一次
这样子我们就可以用静态代码块来创建工厂,达到只执行一次的目的
具体代码如下:
4.5 自己遇到的坑点
- mybatis小鸟插件不显示的问题
- 导入mysql或mybatis坐标版本不对,推荐下面版本
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
- 数据库出错
总结
以上就是第二章的内容,仅仅简单介绍了request和response方法和用法,以及做了一个案例
假如对案例步骤不清楚的可以来观看视频流程
用户登录注册案例视频