Cookie 的概念
Cookie就是若干组键值对。
服务器在响应头中以如下格式设置cookie
l
浏览器将cookie存储在本地,在以后的访问中,在请求中以如下形式发给服务器
关键API
服务器写Cookie
Cookie c=new Cookie("id", "the id is legion"); esponse.addCookie(c); //多个依次重复
服务器读cookie
//从请求头中获取cookie数组 Cookie[] cs=request.getCookies(); //对于数组中每一个Cookie,有getName 和getValue的方法 //分别获取键和值
例子:本例子AServlet写若干cookie,其中一个cookie有key为”id“,
BServlet试图读取该id 的值。
//AServlet Get protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=utf-8"); Cookie c=new Cookie("id", "the id is legion"); response.addCookie(c); Cookie c2=new Cookie("something", "sskalsa"); response.addCookie(c2); response.getWriter().print("i sent you an id in cookie"); } //BServlet Get protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=utf-8"); Cookie[] cs=request.getCookies(); if(cs!=null) { for(Cookie c:cs) { if(c.getName().equals("id")) { String str="获取ID的值为"+c.getValue(); response.getWriter().print(str); } } } }
Cookie 查看和寿命
chrome://settings/content
使用setMaxAge设置cookie寿命,参数单位为秒。服务器回复格式
设置为-1,表示cookie只在内存存在。设置为0,表示通知浏览器在本地彻底删除该cookie。
Cookie路径和语言
设置:cookie.setPath("/cookietest/servlet");
如果请求路径包含了该Cookie路径,那么就会在请求中包含该cookie。
默认路径:如果没有使用setPath,那么cookie 的默认路径算到项目名。
比如访问http://localhost:8080/HelloWeb/AServlet,设置了cookie但没有设置路径,其路径就是/HelloWeb
如何使得所有二级域名共享cookies
cookie.setPath("/"); cookie.setDomain("*.XXX.com");
cookie语言问题
使用URLEncoder.encode和URLDecoder.decode
Sessions
一个例子:说明:登录页面
输入用户名后,以post参数的形式(在body中username=XXXX跳转到LoginServlet
没有登录访问index1.jsp提示“你还没有登录”,如果已经登录,打印出用户名。
核心API。
servlet 中使用HttpSession s=request.getSession();
然后 session.setAttribute("username",name);
index1.jsp 中使用session.getAttribute("username");
所有代码
/////index1.jsp <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Index 1 Page</title> </head> <body> <body> <h1>index1.jsp</h1> <% String username = (String)session.getAttribute("username"); if(username == null) { out.print("您还没有登录!"); } else { out.print("用户名:" + username); } %> <hr/> <a href="/HelloWeb/index2.jsp">index2</a> </body> </body> </html> ////login.jsp <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h1>login.jsp</h1> <hr/> <form action="/HelloWeb/LoginServlet" method="post"> 用户名:<input type="text" name="username" /><br/> <input type="submit" value="Submit"/> </form> </body> </html> //////LoginServlet protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=utf-8"); String name = request.getParameter("username"); if (name.equalsIgnoreCase("rightuser")) { HttpSession session = request.getSession(); session.setAttribute("username", name); response.sendRedirect("/HelloWeb/index1.jsp"); } else { response.getWriter().println("用户名错误"); } }
Cookie
浏览器第一次访问服务器,cookie没有JSESSIONID
服务器返回
以后每次浏览,request头中都携带
使用sessions技术实现图形验证码
响应处理servlet分别打印正确或者错误
为了简化起见,这里不考虑用户名和密码的问题,只考虑验证码是否正确
login的代码
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h1>login.jsp</h1> <hr/> <form action="/HelloWeb/LoginServlet" method="post"> 用户名:<input type="text" name="username" /><br/> 密码: <input type="password" name="password"/><br/> 验证码:<input type="text" name="verifyCode" size=3/> <img id="img" src="/HelloWeb/BServlet"/> <a href="javascript:change()">换一张</a> <br/> <input type="submit" value="Submit"/> </form> <script type="text/javascript"> function change() { var img=document.getElementById("img"); img.src="/HelloWeb/BServlet?a="+new Date().getTime(); } </script> </body> </html>
这里关键的点:
<img id="img" src="/HelloWeb/BServlet"/>
这里BServlet 的代码,BServlet 负责使用VerifyCode类生成随机图形,及其对应的文本。
这里往session中设置了vc的值,
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub VerifyCode vc=new VerifyCode(); BufferedImage image=vc.getImage(); request.getSession().setAttribute("vc", vc.getText()); VerifyCode.output(image, response.getOutputStream()); }
在处理用户请求的LoginServlet中会提取session 中键 vc的值,将其和用户输入的文本进行比较
下面是LoginServlet的代码
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=utf-8"); String scode=(String)request.getSession().getAttribute("vc"); String paramCode=request.getParameter("verifyCode"); if(!paramCode.equals(scode)) { response.getWriter().print("验证码错误"); }else { response.getWriter().println("验证码正确"); } }
辅助类VerifyCode的代码
package com.legion; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.OutputStream; import java.util.Random; import javax.imageio.ImageIO; public class VerifyCode { private int w = 70; private int h = 35; private Random r = new Random(); // {"宋体", "华文楷体", "黑体", "华文新魏", "华文隶书", "微软雅黑", "楷体_GB2312"} private String[] fontNames = {"宋体", "华文楷体", "黑体", "微软雅黑", "楷体_GB2312"}; // 可选字符 private String codes = "23456789abcdefghjkmnopqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ"; // 背景色 private Color bgColor = new Color(255, 255, 255); // 验证码上的文本 private String text ; // 生成随机的颜色 private Color randomColor () { int red = r.nextInt(150); int green = r.nextInt(150); int blue = r.nextInt(150); return new Color(red, green, blue); } // 生成随机的字体 private Font randomFont () { int index = r.nextInt(fontNames.length); String fontName = fontNames[index];//生成随机的字体名称 int style = r.nextInt(4);//生成随机的样式, 0(无样式), 1(粗体), 2(斜体), 3(粗体+斜体) int size = r.nextInt(5) + 24; //生成随机字号, 24 ~ 28 return new Font(fontName, style, size); } // 画干扰线 private void drawLine (BufferedImage image) { int num = 3;//一共画3条 Graphics2D g2 = (Graphics2D)image.getGraphics(); for(int i = 0; i < num; i++) {//生成两个点的坐标,即4个值 int x1 = r.nextInt(w); int y1 = r.nextInt(h); int x2 = r.nextInt(w); int y2 = r.nextInt(h); g2.setStroke(new BasicStroke(1.5F)); g2.setColor(Color.BLUE); //干扰线是蓝色 g2.drawLine(x1, y1, x2, y2);//画线 } } // 随机生成一个字符 private char randomChar () { int index = r.nextInt(codes.length()); return codes.charAt(index); } // 创建BufferedImage private BufferedImage createImage () { BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); Graphics2D g2 = (Graphics2D)image.getGraphics(); g2.setColor(this.bgColor); g2.fillRect(0, 0, w, h); return image; } // 调用这个方法得到验证码 public BufferedImage getImage () { BufferedImage image = createImage();//创建图片缓冲区 Graphics2D g2 = (Graphics2D)image.getGraphics();//得到绘制环境 StringBuilder sb = new StringBuilder();//用来装载生成的验证码文本 // 向图片中画4个字符 for(int i = 0; i < 4; i++) {//循环四次,每次生成一个字符 String s = randomChar() + "";//随机生成一个字母 sb.append(s); //把字母添加到sb中 float x = i * 1.0F * w / 4; //设置当前字符的x轴坐标 g2.setFont(randomFont()); //设置随机字体 g2.setColor(randomColor()); //设置随机颜色 g2.drawString(s, x, h-5); //画图 } this.text = sb.toString(); //把生成的字符串赋给了this.text drawLine(image); //添加干扰线 return image; } // 返回验证码图片上的文本 public String getText () { return text; } // 保存图片到指定的输出流 public static void output (BufferedImage image, OutputStream out) throws IOException { ImageIO.write(image, "JPEG", out); } }