文章目录
- 案例(请求分发案例)
- Response
- 响应行
- 响应头
- 响应体
- 特殊响应头
- refresh
- Content-type
- Content-disposition
- location
- 案例(登录案例)
案例(请求分发案例)
- 场景:有多个请求
Http://localhost:8080/user/login
→ 登录Http://localhost:8080/user/register
→ 注册Http://localhost:8080/user/info
→ 查看用户信息
eg:
/*** localhost:8080/demo1/user/login* localhost:8080/demo1/user/register* localhost:8080/demo1/user/info*///@WebServlet(value = {"/user/login", "/user/register", "/user/info"})
@WebServlet("/user1/*")
public class UserServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {process(req, resp);}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {process(req, resp);}private void process(HttpServletRequest request, HttpServletResponse resp) {String operation = null;// /demo1/user/loginString requestURI = request.getRequestURI();operation = requestURI.substring(requestURI.lastIndexOf("/") + 1);
// if("login".equals(operation)) {
// login(request,resp);
// } else if("info".equals(operation)) {
// info(request,resp);
// }switch (operation) {case "login":login(request, resp);break;case "info":info(request, resp);break;case "register":register(request, resp);break;case "remove":remove(request, resp);break;}}private void remove(HttpServletRequest request, HttpServletResponse resp) {}private void register(HttpServletRequest request, HttpServletResponse resp) {}private void info(HttpServletRequest request, HttpServletResponse resp) {}private void login(HttpServletRequest request, HttpServletResponse resp) {}
}
优化版本:
eg:
DispatchUtil.java
- 通过反射的方式,实现其通用性
public class DispatchUtil {@SneakyThrowspublic static void dispatch(String operation, HttpServletRequest request, HttpServletResponse response, HttpServlet instance) {// java.lang.Class.getDeclaredMethod()方法返回一个Method对象,
// 它反映此Class对象所表示的类或接口的指定已声明方法。
// name 参数是一个字符串,指定所需的方法的简单名称,
// parameterTypes 参数是一个数组的Class对象识别方法的形参类型,在声明的顺序Method method = instance.getClass().getDeclaredMethod(operation, HttpServletRequest.class, HttpServletResponse.class);method.setAccessible(true);method.invoke(instance, new Object[]{request, response});}
}
//@WebServlet(value = {"/user/login", "/user/register", "/user/info"})
@WebServlet("/user2/*")
public class UserServlet2 extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {process(req, resp);}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {process(req, resp);}private void process(HttpServletRequest request, HttpServletResponse resp) {String operation = null;// /demo1/user/loginString requestURI = request.getRequestURI();operation = requestURI.substring(requestURI.lastIndexOf("/") + 1);
// if("login".equals(operation)) {
// login(request,resp);
// } else if("info".equals(operation)) {
// info(request,resp);
// }// 不需要再switch判断,直接写方法名函数就可以DispatchUtil.dispatch(operation, request, resp, this);}private void remove(HttpServletRequest request, HttpServletResponse resp) {}private void register(HttpServletRequest request, HttpServletResponse resp) {}private void info(HttpServletRequest request, HttpServletResponse resp) {}private void login(HttpServletRequest request, HttpServletResponse resp) {}private void logout(HttpServletRequest request, HttpServletResponse resp) {System.out.println("logout");}
}
Response
响应报文的封装,设置响应报文
eg:
HTTP/1.1 200
Vary: accept-encoding,origin,access-control-request-headers,access-control-request-method,accept-encoding
Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Sun, 12-Feb-2023 06:51:56 GMT
Set-Cookie: JSESSIONID=24287278-5ebb-407d-a3f7-56b74782c4c7; Path=/; HttpOnly
Access-Control-Allow-Origin: *
Content-Type: application/json;charset=UTF-8
Date: Mon, 13 Feb 2023 06:51:56 GMT
Content-Length: 200{"errno":0,"data":{"adminInfo":
{"nickName":"admin123","avatar":"https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif"},
"token":"24287278-5ebb-407d-a3f7-56b74782c4c7"},"errmsg":"成功"}
响应行
设置一下响应状态码
方法名 | 参数 | 说明 |
---|---|---|
setStatus(int) | 参数就是状态码 | 设置响应状态码 |
eg:
/*** 常用的响应状态码:200、404、302、400、500* 响应行中的响应状态码*/
@WebServlet("/line")
public class LineServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse response)throws ServletException, IOException {response.setStatus(302);}
}
响应头
- 响应头是
key:value
的格式,提供了通用的方法,可以设置响应头的key和value - 提供了一些特定的方法,特定的方法做的事情,就是设置特定响应头的值
方法 | 参数 | 说明 |
---|---|---|
setHeader(String,String) | 参数1提供key,参数2提供value | 通用的方法 |
eg:
@WebServlet("/header")
public class HeaderServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse response)throws ServletException, IOException {// 第一个参数是key,第二个参数是valueresponse.setHeader("custom-header","aaaaaa");}
}
响应体
- 可以使用字符流,也可以使用字节流
- 场景:
- 字符流:响应文本数据,最主要的场景就是前后端分离之后,通过字符流响应Json数据
- 字节流:响应图片、文件,也通常在文件下载的场景下使用
方法 | 返回值 | 描述 |
---|---|---|
getWriter() | PrintWriter | 字符流 |
getOutputStream() | ServletOutputStream | 字节流 |
eg:
- 字符流举例
@WebServlet("/body1")
public class BodyServlet1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse response)throws ServletException, IOException {// response.getWriter().write("hello world");// 如果把响应体里的字符以utf-8的方式编码,不一定能解决中文乱码的问题// 因为浏览器不一定以utf-8的方式来解码// 从根本上解决这个问题通知浏览器以utf-8的方式解码// content-type:指响应体里的正文类型response.setHeader("content-type","text/html;charset=utf-8");// response.getWriter().write("hello world");// 默认的编码:iso-8859-1response.getWriter().println("hello world");}
}
- 字节流举例
@WebServlet("/body2")
public class BodyServlet2 extends HttpServlet {// http://localhost:8080/demo1/body2?pic=1.jpg@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {String pic = request.getParameter("pic");String path = "D:\\test_photo";File file = new File(path, pic);// 要显示图片,需要在响应体中提供其字节数据 -> 浏览器就会显示图片ServletOutputStream outputStream = response.getOutputStream();FileInputStream inputStream = new FileInputStream(file);int length = 0;byte[] bytes = new byte[1024];while((length = inputStream.read(bytes)) != -1) {outputStream.write(bytes, 0 ,length);}inputStream.close();outputStream.close();}
}
特殊响应头
- 特殊的几个响应头:
refresh
→ 定时刷新、跳转content-type
→ 限定响应的正文(也可以解决中文乱码问题)content-disposition
→ 文件下载location
→ 重定向
refresh
eg:
/*** 自动显示当前的时间*/
@WebServlet("/refresh")
public class RefreshServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse response)throws ServletException, IOException {response.setHeader("refresh", "1");String pattern = "yyyy-MM-dd HH:mm:ss";SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);String dateStr = simpleDateFormat.format(new Date());response.getWriter().println(dateStr);}
}
@WebServlet("/refresh2")
public class RefreshServlet2 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse response)throws ServletException, IOException {// 指3s之后去访问demo2/hello.jspresponse.setHeader("refresh", "3;url=/demo1/hello.jsp");response.setContentType("text/html;charset=utf-8");response.getWriter().println("请稍后马上跳转到欢迎页面");}
}
Content-type
- 通常不需要设置
- 比如我们响应Json数据给前端,我们可以设置
Content-Type:application/json
- 我们要在这里做字符集的设置,如果没有做有可能出现中文乱码
Content-disposition
- 下载的场景会使用
- eg:
content-disposition: attachment;filename=1.jpg
- 以
1.jpg
来下载正文
- eg:
eg:
@WebServlet("/download")
public class ContentDispositionServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {String pic = request.getParameter("pic");String path = "D:\\test_photo";// 如果代码没有这行内容,那么就是显示该图片// 如果做下载,需要设置header content-dispositionresponse.setHeader("content-disposition", "attachment;" + pic);FileInputStream inputStream = new FileInputStream(new File(path, pic));ServletOutputStream outputStream = response.getOutputStream();int length = 0;byte[] bytes = new byte[1024];while ((length = inputStream.read(bytes)) != -1) {outputStream.write(bytes, 0, length);}inputStream.close();}
}
location
- 重定向
- 状态码:
302
eg:
@WebServlet("/location")
public class LocationServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {System.out.println("访问到LocationServlet");resp.setStatus(302);resp.setHeader("location","http://localhost:8080/demo1/refresh");}
}
案例(登录案例)
- 这个请求由登录页面提供,我们可以通过html提供一个登录表单,该表单会发出请求
http://localhost:8080/user/login
→ Servlet → 检查用户名和密码是否正确(使用一下MyBatis) →
- 如果正确,那么就提示登录成功
- 如果错误,那么刷新登录页面
任务拆解:
- 包含登录表单的 login.html文件,放在webapp目录下
- 开发UserServlet
- /user/login对应的处理方法,使用MyBatis做查询
- /user/info对应的处理方法
- 整合MyBatis,在应用程序中维护SqlSessionFactory实例
- Mybatis的配置:
public interface UserMapper {List<User> selectByUserNameAndPassword(@Param("username") String username, @Param("password") String password);User selectByPrimaryKey(Integer id);
}
<mapper namespace="com.coo1heisenberg.demo2.mapper.UserMapper"><select id="selectByUserNameAndPassword" resultType="com.coo1heisenberg.demo2.bean.User">select id, username, password, age, birthday, createDate, mobile from test_user<where>username = #{username} and password = #{password}</where></select><select id="selectByPrimaryKey" resultType="com.coo1heisenberg.demo2.bean.User">select id, username, password, age, birthday, createDate, mobile from test_user<where>id = #{id}</where></select>
</mapper>
- Servlet的配置
@WebServlet("/user/*")
public class UserServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {process(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {process(req, resp);}private void process(HttpServletRequest request, HttpServletResponse response) {String requestURI = request.getRequestURI();String operation = null;operation = requestURI.substring(requestURI.lastIndexOf("/") + 1);switch (operation) {case "login":login(request, response);break;case "info":info(request, response);break;}}@SneakyThrowsprivate void info(HttpServletRequest request, HttpServletResponse response) {Object user = request.getAttribute("user");response.getWriter().println(user);}@SneakyThrowsprivate void login(HttpServletRequest request, HttpServletResponse response) {// 1. 首先获得username和passwordString username = request.getParameter("username");String password = request.getParameter("password");// 2. 查询user记录UserMapper userMapper = MybatisUtil.getSqlSession().getMapper(UserMapper.class);List<User> users = userMapper.selectByUserNameAndPassword(username, password);// 3. 根据user记录判断登录状态response.setContentType("text/html;charset=utf-8");// 4. 判断登录状态 user的list是否为空if (users == null || users.size() == 0) {// 如果登陆失败(list == null || list.size() == 0)// 刷新到refresh --> 2;url=/demo2/login.html// 响应登录失败信息response.getWriter().println("登录失败,即将跳转登录页面");response.setHeader("refresh", "2;url=/demo2/login.html");} else {// 如果登录成功(list.size > 0)// 响应登录成功信息response.getWriter().println("登录成功");request.setAttribute("user", users.get(0));request.getRequestDispatcher("/user/info").forward(request, response);// 跳转到info -> 分享user的id信息(直接分享user信息)}}
}
- HTML的配置
<body>
<h1>登录页面</h1>
<!--action:表示当前表单中的内容提交给哪个页面进行处理-->
<!--method:表示当前表单提交的方式,常见的有get和post方式,默认是get提交-->
<form action="/demo2/user/login" method="post">用户名:<input type="text" name="username"><br>密码:<input type="password" name="password"><br><input type="submit">
</form></body>