Servlet
HttpServletRequest应用
实现一个代码,让浏览器把请求的相关信息全部显示出来
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
String url = req.getRequestURI();
String protocol = req.getProtocol();
String query = req.getQueryString();
Enumeration headNames = req.getHeaderNames();
String referer = req.getHeader("Referer");
String host = req.getHeader("Host");
String contentType = req.getContentType();
int contentLength = req.getContentLength();
String contentTyppe2 = req.getHeader("Content-Type");
String contentLength2 = req.getHeader("Content-Length");
String string = String.format("<div> method = %s <div>",method) ;
string += String.format("<div> url = %s <div>",url) ;
string += String.format("<div> protocol = %s <div>",protocol) ;
string += String.format("<div> query = %s <div>",query) ;
string += String.format("<div> headNames = %s <div>",headNames.toString()) ;
string += String.format("<div> referer = %s <div>",referer) ;
string += String.format("<div> host = %s <div>",host) ;
string += String.format("<div> contentLength = %d <div>",contentLength) ;
string += String.format("<div> contentTyppe2 = %s <div>",contentTyppe2) ;
string += String.format("<div> contentLength2 = %s <div>",contentLength2) ;
resp.setContentType("text/html");
resp.getWriter().write(string);
}
HttpServletResponse应用
实现一个代码,让浏览器展示页面时,每秒刷新一次
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 需要在http响应的head中加上一个refresh,值为间隔的秒数
// 构造一个响应页面,这个页面每秒刷新一次
// 用这个方法 System.currentTimeMillis() 获取当前时间戳
String str = "<h3>"+ System.currentTimeMillis() +"</h3>" ;
resp.setHeader("Refresh","1");
resp.setContentType("text/html");
resp.getWriter().write(str);
}
状态码
设置不同的状态码
404 状态码表示的是Not Found,但是也可以由程序员自己来设定页面内容,Tomcat自身也实现了一个404,平时看到的很多404都是Tomcat自己的页面
很多网站的404都有自己的风格,如:chrome 浏览器的404是一个小游戏,支付宝的404是寻找丢失的儿童
如果我们也想用一下Tomcat的404页面也是可以的:
public class Serlet404 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.sendError(404,"404040404404");
}
}
或者直接设置状态码
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(404);
resp.getWriter().write("Status = 404");
}
设置一个重定向页面:(注意,此处的url必须是完整的,简写会出错)
public class LocationServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(302);
resp.setHeader("Location","https://www.baidu.com/");
}
}
或者直接设置:(简化版)
public class LocationServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.sendRedirect("https://www.baidu.com/");
}
}
Cookie和Session
客户端进行身份验证,把身份信息通过请求发送给服务器
服务器收到请求,根据信息验证身份,分配一个Session对象,并生成一个SessionId,通过响应中的Set-Cookie属性发送给客户端
客户端拿到Set-Cookie的值,就会保存到浏览器本地
再次验证就会自动带上之前Cookie中保存的值,服务器通过Cookie的值就可以查询用户的身份信息了
SetCookie
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie cookie = new Cookie("time",""+System.currentTimeMillis());
resp.addCookie(cookie);
resp.setStatus(200);
resp.setContentType("text/html");
resp.getWriter().write("<div>客户端存储cookie</div>");
}
GetCookie
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie[] cookie = req.getCookies();
for (Cookie c:cookie) {
System.out.println(c.getName() + " = " + c.getValue());
}
resp.setContentType("text/html");
resp.getWriter().write("<h3>服务器获取到cookie</h3>");
}
先访问GetCookie,就会500,提示内部服务器错误,需要先访问SetCookie,然后再访问GetCookie,这样一来,访问GetCookie时,就会带有Cookie字段,从而访问成功。
还可以通过setMaxAge
这个方法来设置Cookie的过期时间,时间一到,浏览器就会自动删除这个Cookie,就需要重新登陆了
Session:
虽然 Servlet 给我们提供了Cookie的一些操作,但是实际上,很少会直接操作Cookie,最主要的目的就是识别用户身份,直接使用Session也可以达到这样的效果。
在 HttpServletRequest 里有一个getSession
方法,当参数为false时,直接返回,有就是有,没有就是没有(null)。参数为true时,没有Session就会创建一个Session。返回值为HttpSession
Session可以理解为一个会话,每一个用户访问服务器时,服务器都会给用户分配一个会话,服务器给多个用户服务,就存在多个会话,每个会话对象里都包含一些键值对属性,通过getAttribute()
来获取某个键值对 setAttribute
来设置键值对 removeAttribute
移除键值对
判断当前会话是否存在的依据是SessionId,调用getSession()
时,会先尝试在请求的Cookie中,有没有SessionId,如果没有SessionId,那么就会直接创建一个键值对,同时把这个SessionId通过Set-Cookie返回给浏览器,如果有SessionId,就查一下是否存在这个SessionId,如果不存在,还是要创建一个键值对,再通过Set-Cookie返回给浏览器,如果存在,直接通过SessionId查找对应的HttpSession对象即可
每个SessionId对应不同的HttpSession对象
也可以理解为在登陆机制中,只用Cookie还不够,还要用到Session
保存会话信息是在内存中,如果重启Tomcat,那么服务器端保存的会话信息就会丢失,如果不想丢失保存的会话信息,就可以把保存的会话信息放在磁盘上,如:保存在数据库里
服务器重启后,服务器端数据丢失,但客户端数据仍然在,所以请求中虽然会带有Cookie字段,但是服务器并不能识别或匹配,所以需要重新登陆一次。
在响应中,就可以找到SessionId、Path等信息在Set-Cookie中
一般来说,只有在login的时候,获取session时填写true,其它情况一般填写false
一个简单的登陆界面
登陆界面:
<form action="login" method="post">
<div>
用户名<input type="text" name="username">
</div>
<div>
密码<input type="password" name="password"></div>
<div>
<input type="submit" name="提交">
</div>
</form>
登陆成功的界面(跳转至主页)
@WebServlet("/login")
public class Login extends HttpServlet {
private String username = "lit";
private String password = "lit";
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
resp.setContentType("text/html;charset = utf-8");
if (username == null || "".equals(username) || password == null || "".equals(password)){
resp.setStatus(403);
resp.getWriter().write("<h3>登陆失败</h3>");
return;
}
if (username.equals(this.username)&&password.equals(this.password)){
resp.getWriter().write("<h3>登陆成功</h3>");
}else {
resp.setStatus(403);
resp.getWriter().write("<h3>登陆失败</h3>");
return;
}
HttpSession httpSession = req.getSession(true);
httpSession.setAttribute("username",username);
httpSession.setAttribute("time",System.currentTimeMillis());
httpSession.setAttribute("visitCount",0);
resp.setStatus(200);
String html = String.format("<h3>登陆成功! 3s 之后跳转到主页</h3>");
//这段代码意为:再设置的3000ms时间后执行function里的代码,借助JS代码里的定时器实现
//此处也可以使用setInterval 也是JS定时器,只不过可以实现多个setTimeout的效果。(如:时间递减)
html += "<script> setTimeout(function() { location.assign(\"index\"); }, 3000); </script>";
resp.getWriter().write(html);
}
}
主页:
@WebServlet("/index")
public class IndexServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset = utf-8");
// 确认当前用户是否已经登陆
HttpSession session = req.getSession(false);
//为false时,没有session就会返回null
if (session == null){
resp.sendRedirect("login.html");
return;
}
String name = (String) session.getAttribute("username");
Long time = (Long) session.getAttribute("time");
int visitCount = (Integer) session.getAttribute("visitCount");
visitCount += 1;
session.setAttribute("visitCount",visitCount);
String html = String.format("<div>欢迎 %s</div>",name);
html += String.format("<div>上次访问时间: %d</div>",time);
html += String.format("<div>访问次数:%s</div>",visitCount);
resp.getWriter().write(html);
}
}
上传文件
上传文件(浏览器选择一个本地的文件,把文件提交到服务器上)需要再页面上通过form表单做出一些支持,服务器也会通过Servlet做出支持
上传文件时的数据类型就需要做出修改Content-Type = multipart
上传文件后服务器要获取文件就要通过Part对象,要调用Part对象,就要使用@MultipartConfig
注解
代码如下:
html
<h3>上传文件</h3>
<form action="uplode" method="post" enctype="multipart/form-data">
<div>
<input type="file" name="lit">
</div>
<div>
<input type="submit" value="提交">
</div>
</form>
实现代码:
@MultipartConfig
@WebServlet("/uplode")
public class UpLodeServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//首先通过req.getPart()就能拿到一个Part对象,一个Part对象就能对应到一个上传的文件,一个http亲求中可以有多个Part对应多个文件
Part part =req.getPart("lit");
part.write("d:/lit.jpg");
String name = part.getName();
String fileName = part.getSubmittedFileName();
String type = part.getContentType();
long size = part.getSize();
resp.setContentType("text/html;charset = utf-8");
resp.getWriter().write("<div>上传成功</div>");
}
}
这种方式只适合上传小文件
如果要上传1g左右的大文件,就需要考虑断点续传(再客户端把文件做出处理,用JS把文件切割成若干份。传到服务器后,服务器需要记录当前已经传了哪些份的数据。)