案例一、完成用户注册
案例二、完成登录错误信息的回显
1.request的运行流程
2.通过抓包工具抓取Http请求
3.通过request获得请求行
获得客户端的请求方式(get\post等):String getMethod()
获得请求的资源:
!!! String getContextPath() ---web应用程序的路径,以/开头
String getQueryString() ---- get提交url地址后的参数字符串,资源路径后面?username=zhangsan&password=123
public class LineServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1、获得请求方式
String method = request.getMethod();
System.out.println("method:"+method);
//2、获得请求的资源相关的内容
String requestURI = request.getRequestURI();
StringBuffer requestURL = request.getRequestURL();
System.out.println("uri:"+requestURI);
System.out.println("url:"+requestURL);
//获得web应用的名称
String contextPath = request.getContextPath();
System.out.println("web应用:"+contextPath);
//地址后的参数的字符串
String queryString = request.getQueryString();
System.out.println(queryString);
//3、获得客户机的信息---获得访问者IP地址
String remoteAddr = request.getRemoteAddr();
System.out.println("IP:"+remoteAddr);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
打印台输出:
get方式
post方式---url后面 为null
4.通过request获得请求体
String getParameter(String name)----- --获取某个指定名称的参数值(username)
String[] getParameterValues(String name)---------多个相同名称的参数(hobbies)
Enumeration getParameterNames()
Map<String,String[]> getParameterMap()----- getParameterMap() 方法将所有请求消息中的参数名和值装入一个MAP中
-
编写ConteneServlet
Map<String,String[]> getParameterMap() 装入map中,所以先循环entry.key,在循环打印entry.value(value此处是数组对象)
//1、获得单个表单值
String username = request.getParameter("username");
System.out.println(username);
String password = request.getParameter("password");
System.out.println(password);
//2、获得多个表单的值
String[] hobbys = request.getParameterValues("hobby");
for(String hobby:hobbys){
System.out.println(hobby);
}
//3、获得所有的请求参数的名称
Enumeration<String> parameterNames = request.getParameterNames();
while(parameterNames.hasMoreElements()){
System.out.println(parameterNames.nextElement());
}
System.out.println("------------------");
//4、获得所有的参数 参数封装到一个Map<String,String[]>
Map<String, String[]> parameterMap = request.getParameterMap();
for(Map.Entry<String, String[]> entry:parameterMap.entrySet()){
System.out.println(entry.getKey());
for(String str:entry.getValue()){
System.out.println(str);
}
System.out.println("---------------------------");
}
-
浏览器输入网址
回车提交订单
演示如下:
5.request的其他功能
(1)request是一个域对象
request对象也是一个存储数据的区域对象,所以也具有如下方法:
setAttribute(String name, Object o)---将一个对象与一个名称关联后存入ServletRequest对象中
getAttribute(String name)------从ServletRequest对象中返回指定名称的属性
removeAttribute(String name)
注意:request域的作用范围:一次请求中
(2)request完成请求转发
获得请求转发器----path是转发的地址
RequestDispatcher dispatcher = request.getRequestDispatcher(String path);
通过转发器对象转
requestDispathcer.forward(ServletRequest request, ServletResponse response)
eg:
-
编写RequestForwardServlet
-
编写ResultServlet
-
结果
事例一-------注册:
若一条条填写输入注册用户的信息,从username 、password、email、birthday写起来太麻烦了,我们考虑用一个BeanUtils进行封装,将map中的数据根据key与实体的属性的对应关系封装,只要key的名字与实体的属性 的名字一样,就自动封装到实体中
-
创建实体User.java
-
编写RegisterServlet
BeanUtils 是 Apache commons组件的成员之一,主要用于简化JavaBean封装数据的操作。它可以给JavaBean封装一个字符串数据,也可以将一个表单提交的所有数据封装到JavaBean中。
public class RegisterServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//设置request的编码---只适合post方式
request.setCharacterEncoding("UTF-8");
//get方式乱码解决
//String username = request.getParameter("username");//乱码
//先用iso8859-1编码 在使用utf-8解码
//username = new String(username.getBytes("iso8859-1"),"UTF-8");
//1、获取数据
//String username = request.getParameter("username");
//System.out.println(username);
//String password = request.getParameter("password");
//.....
//2、将散装的封装到javaBean
//User user = new User();
//user.setUsername(username);
//user.setPassword(password);
//使用BeanUtils进行自动映射封装
//BeanUtils工作原理:将map中的数据 根据key与实体的属性的对应关系封装
//只要key的名字与实体的属性 的名字一样 就自动封装到实体中
Map<String, String[]> properties = request.getParameterMap();
User user = new User();
try {
BeanUtils.populate(user, properties);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
//现在这个位置 user对象已经封装好了
//手动封装uid----uuid---随机不重复的字符串32位--java代码生成后是36位
user.setUid(UUID.randomUUID().toString());
//3、将参数传递给一个业务操作方法
try {
regist(user);
} catch (SQLException e) {
e.printStackTrace();
}
//4、认为注册成功跳转到登录页面
response.sendRedirect(request.getContextPath()+"/login.jsp");
}
//注册的方法
public void regist(User user) throws SQLException{
//操作数据库
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
String sql = "insert into user values(?,?,?,?,?,?,?,?,?,?)";
runner.update(sql,user.getUid(),user.getUsername(),user.getPassword(),user.getName(),
user.getEmail(),null,user.getBirthday(),user.getSex(),null,null);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
注意:
在用户注册成功之后会跳转到登陆页面,这个时候用重定向而不是转发,原因如下:
1)用户体验,url地址栏应该对应成login.jsp而不是停留在register.jsp
2)用户刷新网页之后访问的仍然是register.jsp,意味着代码再跑一遍,给服务器增加压力,且之前信息丢失了。
此处重定向用的是response.sendRedirect ( request.getContextPath( ) + "/ login.jsp ");
而不是response.sendRedirect ('' / web15 / login . jsp"); 若是要修改项目名称,将web15改成ABC,就获取不到web下面的jsp页面了,所以用request.getContextPath( ) 动态的获取web应用的路径名称。
事例二-------登陆:
LoginServlet方法
逻辑:
1、获得用户名和密码
2、调用一个业务方法进行该用户查询
3、通过user是否为null判断用户名和密码是否正确
如果用户不为空,则用户名和密码正确,登录成功 跳转到网站的首页
否则用户名或密码错误,使用转发,转发到login.jsp,向request域中存储错误信息
public class LoginServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
//1、获得用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
//2、调用一个业务方法进行该用户查询
User login = null;
try {
login = login(username,password);
} catch (SQLException e) {
e.printStackTrace();
}
//3、通过user是否为null判断用户名和密码是否正确
if(login!=null){
//用户名和密码正确
//登录成功 跳转到网站的首页
response.sendRedirect(request.getContextPath());
}else{
//用户名或密码错误
//跳回当前login.jsp
//使用转发 转发到login.jsp 向request域中存储错误信息
request.setAttribute("loginInfo", "用户名或密码错误");
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
}
//定义一个login方法,返回user注册信息,若登陆成功则user不为空
public User login(String username,String password) throws SQLException{
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
String sql = "select * from user where username=? and password=?";
User user = runner.query(sql, new BeanHandler<User>(User.class), username,password);
return user;
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
用户名或密码错误,使用转发,转发到login.jsp,向request域中存储错误信息 。其实jsp也是一个servlet,可以镶嵌java代码。
在login.jsp加入这么一段,若loginInfo为空则说明登录成功,不显示“”,若不为空则说明登录失败,显示错误信息。
NOTICE:产生乱码的原因:
解决post提交方式的乱码:request.setCharacterEncoding("UTF-8");
解决get提交的方式的乱码:
parameter = new String(parameter.getbytes("iso8859-1"),"utf-8");
总结
1):
对比 | ServletContext: | request: |
创建 | 服务器启动 | 访问时创建request |
销毁 | 服务器关闭 | 响应结束request销毁 |
域的作用范围 | 整个web应用 | 一次请求中 |
转发 | 重定向 | |
请求次数 | 一次请求一次响应 | 两次请求两次响应 |
地址栏 | 地址不变 | 地址变化 |
访问资源 | 只能访问内部资源 | 可以访问外部网站 |
性能 | 优于重定向 |
重定向路径需要加web应用名称 转发不需要写web应用的名称
总结:
request获得行的内容
request.getMethod()
request.getRequestURI()
request.getRequestURL()
request.getContextPath()
request.getRemoteAddr()
request获得头的内容
request.getHeader(name)
request获得体(请求参数)
String request.getParameter(name)
Map<String,String[]> request.getParameterMap();
String[] request.getParameterValues(name);
注意:客户端发送的参数到服务器端都是字符串
获得中文乱码的解决:
post: request.setCharacterEncoding(“UTF-8”);
get: parameter = new String(parameter.getBytes(“iso8859-1”),”UTF-8”);
request转发和域
request.getRequestDispatcher(转发的地址).forward(req,resp);
request.setAttribute(name,value)
request.getAttribute(name)