会话 Cookie和Session
会话概述
BS结构的程序类似于打电话,从浏览器第一次访问服务器开始,服务器就创建了一个会话。整个过程中,浏览器不断地向服务器发送请求,服务器也不断向浏览器做出响应,这个过程就称为一个会话。当用户关闭浏览器的时候,这个会话就结束。
两种会话技术
有两种技术实现浏览器与服务器之间的会话:Cookie和Session
Cookie
Creates a cookie, a small amount of information sent by a servlet to a Web browser, saved by the browser, and later sent back to the server. A cookie’s value can uniquely identify a client。
创建一个Cookie,通过Servlet发送给浏览器的少量的信息,保存在浏览器,然后再由浏览器发送回给服务器,一个Cookie的值能够唯一标识一个客户端。
格式:一个Cookie对象就是一个键值对,键和值都是字符串类型
原理:
1) 第一次浏览器访问服务器的时候,没有Cookie。
2) 由Servlet服务器创建Cookie,以响应头Set-Cookie的方式发送给浏览器。
3) 浏览器接收到Cookie以后,存储到浏览器端。
4) 后续再访问服务器,将Cookie的信息以请求头:Cookie的方式发送给服务器。
Cookie操作相关的方法
创建Cookie
- Cookie(String name,String value) 构造方法,没有无参的构造方法。键和值都是字符串类型
- String getName() 得到Cookie的名字
- String getValue() 得到Cookie的值
Cookie的写入响应方法:
- response.addCookie(cookie对象)
- 将Cookie对象返回给浏览器
示范:
//1. 创建Cookie
Cookie user = new Cookie("name", "NewBoy");
//2. 通过响应对象写入Cookie到浏览器
response.addCookie(user);
查询响应头Response Hears的显示:
Set-Cookie: name=NewBoy
Cookie的过期时间
默认是浏览器关闭以后,当前Cookie失效
方法:
- void setMaxAge(int expiry) 设置Cookie过期时间,单位是秒。
代码:
//1. 创建Cookie
Cookie user = new Cookie("name", "NewBoy");
//设置Cookie过期的时间
user.setMaxAge(60 * 10);
//2. 通过响应对象写入Cookie到浏览器
response.addCookie(user);
结果的到期时间:
Cookie的读取:
Cookie[] request.getCookies()
- 读取浏览器端发送过来的所有的Cookie,返回Cookie的数组
代码:
PrintWriter out = response.getWriter();
//1.读取Cookie,返回数组
Cookie[] cookies = request.getCookies();
//2. 先判断数组是否为空,如果没有Cookie返回null
if (cookies !=null) {
//进行遍历操作
for (Cookie cookie : cookies) {
out.print("Cookie的名字:" + cookie.getName() + ", Cookie的值:" + cookie.getValue() + "<br/>");
}
}
else {
out.print("没有任何的Cookie");
}
out.close();
Cookie中使用汉字的情况
Cookie中不支持直接使用汉字,如果要使用汉字的话,需要进行URL编码。直接使用汉字报错:
- java.net.URLEncoder.encode(“字符串”,”utf-8”)
- 对字符串进行URL编码
- java.net.URLDecoder.decode(“字符串”,”utf-8”)
- 对字符串进行URL解码
创建Cookie并把中文编码
Cookie user=new Cookie("name",URLEncoder.encode("你好","utf-8"));
response.addCookie(user);
获得所有的Cookie并把中文解码输出
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
writer.print("name: "+cookie.getName()+" | value: "+URLDecoder.decode(cookie.getValue(),"utf-8")+"<br/>");
}
设置Cookie的路径
设置路径的方法
Cookie设置路径的方法
cookie.setPath(路径);
- 设置浏览器向服务器发送Cookie的访问路径
只有访问指定的路径或它的子路径,请求才将Cookie的信息发送给服务器
默认的路径:
如果没有设置访问路径,默认是当前的项目访问路径
http://localhost:8080/项目名/
演示:创建一个Cookie,设置过期时间,设置Cookie的访问路径
Set-Cookie: name=Jack; Expires=Wed, 03-Jan-2018 02:18:14 GMT; Path=/aaa
问:
如果访问路径是setPath(“/day39-cookie”),以下路径哪些可以正常访问Cookie?
访问地址 | 能否访问到Cookie |
---|---|
http://localhost:8080/day39-cookie/ | 可以 |
http://localhost:8080/day39-cookie/aaa/bbb | 可以 |
http://localhost:8080/day39-aaa | 不可以 |
http://localhost:8080/ | 不可以 |
Cookie的删除
cookie.setMaxAge()
- 将过期的时间设置为0,表示删除Cookie
//删除指定的Cookie
Cookie visitedTime = new Cookie("visitedTime", "");
//删除Cookie,过期的时间设置为0
visitedTime.setMaxAge(0);
//写入到浏览器
response.addCookie(visitedTime);
案例
需求
1) 如果用户是第一次访问,则输出:您好,您是第1次访问,当前的时间是xxx
2) 把这次访问服务器的时间写到Cookie中
3) 如果之前已经访问过,则从Cookie中得到上次访问的时间,显示:您好,欢迎您再次访问。
上次访问的时间是:xxxx,当前的时间是xxxxx。
代码:
CookieUtils
public class CookieUtils {
/**
* 从Cookie数组中取一个名字为name的值,如果有则返回值,没有则返回空。
*/
public static String getCookieValue(HttpServletRequest request , String name) {
//1. 得到所有的Cookie
Cookie[] cookies = request.getCookies();
//2. 如果数组不为空,遍历数组
if (cookies!=null) {
for (Cookie cookie : cookies) {
//3. 比较每个名字是否与name相等,如果相等返回它的值
if (cookie.getName().equals(name)) {
return cookie.getValue();
}
}
}
//没有找到
return null;
}
}
Servlet
// 1) 得到当前时间
String time = new Timestamp(System.currentTimeMillis()).toString();
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
// 2). 从Cookie中取一个叫visitedTime的信息,如果为null,则表示第一次访问
String value = CookieUtils.getCookieValue(request, "visitedTime");
if (value == null) {
out.print("<h1>欢迎您的第1次访问,现在的时间是:" + time + "</h1>");
}
// 3). 否则读取Cookie的信息,并且显示上次访问的时间
else {
out.print("<h2>欢迎再次访问,您上次访问的时间是:" + value + "</h2>");
out.print("<h2>这次的时间是:" + time + "</h2>");
}
// 4). 无论上次访问时间是否为空,都把这次访问的时间写入Cookie中
Cookie cookie = new Cookie("visitedTime", time);
// 设置过期时间
cookie.setMaxAge(60 * 60 * 24 * 30 * 6);
// 写入浏览器
response.addCookie(cookie);
out.close();
HttpSession会话
Session技术的特点:
1) 数据保存在服务器的内存中,底层是一个Map对象
2) 每一个用户对应一个会话
3) 不同的会话之间数据不能共享的
Session和Cookie的主要区别在于:
1) Cookie的数据是存在浏览器端缓存中
2) Session的数据是存在服务器的内存中
HttpSession的使用
创建Session的注意事项
Hession session=request.getSession();
在获得会话时候,要注意会话是否过期(用户在页面停留太久没有操作),如果session
过期再调用会话的方法会出错,因为过期了获得会话的时候是新创建一个session
的
所以转化成
- Hession session =request.getSession(true);
- Hession session =request.getSession(false);
getSession(boolean create)意思是返回当前reqeust中的HttpSession ,当create为true,就创建一个新的Session,否则当create为fasle时候,没有session时返回null;
简而言之:
HttpServletRequest.getSession(ture) 等同于 HttpServletRequest.getSession()
HttpServletRequest.getSession(false) 等同于 如果当前Session没有就为null;
创建会话的时机:
用户第一次访问服务器,并且调用request.getSession()方法,创建一个会话对象HttpSession对象。如果当前会话没有,则创建一个,如果有则得到原有的会话对象。
HttpSession接口方法
String getId()
- 得到当前会话的ID,每个会话都有一个唯一的ID,是一个32位的十六进制数。不同的用户会话ID是不同的,不同的浏览器就是不同的用户
long getCreationTime()
- 得到会话创建的时间,返回的是1970-1-1到创建时间相差的毫秒数
long getLastAccessedTime()
- 得到会话最后访问的时间,上一次的访问时间
boolean isNew()
- 判断是否是一个新的会话,新的会话返回true
ServletContext getServletContext()
- 可以通过会话对象得到上下文对象
示范
//得到会话
HttpSession session = request.getSession();
out.print("您的会话ID是:" + session.getId() + "<br/>");
out.print("会话创建的时间:" + new Timestamp(session.getCreationTime()) + "<br/>");
out.print("上一次访问的时间:" + new Timestamp(session.getLastAccessedTime()) + "<br/>");
out.print("现在的时间:" + new Timestamp(System.currentTimeMillis()) + "<br/>");
out.print("是否是新的会话:" + session.isNew() + "<br/>");
分析原理
SetServlet:
// 向会话域中添加值
HttpSession session = request.getSession();
session.setAttribute("product", "洗衣机");
GetServlet:
//从会话域中取出值
HttpSession session = request.getSession();
out.print(session.getAttribute("product"));
HTTP协议是无状态协议,不能保存用户的状态信息。如何知道这是否是同一个用户呢?
查看SetServlet中的响应头:
将会话的ID通过Cookie发送给浏览器,浏览器可以得到这个Cookie
Set-Cookie: JSESSIONID=921E1BA691655F94D74C6E28345A4CE0; Path=/day39-session/; HttpOnly
2) 查看GetServlet的请求头:
`Cookie: JSESSIONID=921E1BA691655F94D74C6E28345A4CE0`
下次再访问的时候,将这个Cookie发送给服务器,服务器读取Cookie信息,和服务器中的会话ID进行比较,如果相等,表示是同一个用户。
可以理解服务器创建SessionID的时候,也创建了一个Cookie,然后把SessionID放进去Cookie然后一起响应给浏览器
```
//创建Cookie
Cookie cookie = new Cookie("JSESSIONID", session.getId());
//写到浏览器中
response.addCookie(cookie);
```
会话的原理分析:
1) 浏览器第1次服务器,服务器通过getSession()创建一个会话对象。并且分配一个会话ID。
2) 通过Set-Cookie,将JSESSIONID发送给浏览器。
3) 下次访问浏览器将Cookie发送给服务器,服务器得到会话ID,与所有的会话比较,找到它所对应会话。
4) 不同浏览器的ID是不同的。
5) 同一个浏览器关闭以后,Cookie过期,再次打开浏览器,得不到原来的会话ID。
HttpSession的分析
如果浏览器关闭,服务器上的会话信息是否还存在?
答:只要会话没有过期,服务器上的会话信息是存在。
原因:
为什么取不到原来的数据,因为会话ID丢失。所以不能得到原来的会话信息。
方案:
可以将会话ID写到Cookie中,设置Cookie的过期时间。
Set-Cookie:JSESSIONID=BD324DB78ED6E0BBBCBE11F4150EADAE; Path=/day39-session/; HttpOnly
Set-Cookie:JSESSIONID=BD324DB78ED6E0BBBCBE11F4150EADAE; Expires=Wed, 03-Jan-2018 04:42:12 GMT
代码:
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 向会话域中添加值
HttpSession session = request.getSession();
//创建Cookie
Cookie cookie = new Cookie("JSESSIONID", session.getId());
//设置Cookie过期时间
cookie.setMaxAge(60 * 60);
//写到浏览器中
response.addCookie(cookie);
session.setAttribute("product", "洗衣机");
}
个人的话
不同浏览器有不同的会话Id 不同的Session,sessionID是基于Cookie发送给服务器的,一个浏览器关闭后或者Cookie关闭后,sessionID就会丢失,为了不让丢失可以设置Cookie的生命周期,但是太久也没用,因为服务器端也有sessionID的生命周期,默认1800秒,30分钟,
疑问:Session在服务器上默认的销毁时间是多久?如何查看?
session.getMaxInactiveInterval()
- 最大非活动时间间隔,单位是秒。默认是30分钟
代码:
HttpSession session=request.getSession();
//获得服务器的生命周期
out.print("服务器会话过期的时间:"+session.getMaxInactiveInterval()+"秒");
结果:
改变会话的生命周期:
方式一:
session.setMaxInactiveInterval(秒)
- 修改会话过期的时间,单位是秒
在指定的时间内如果与服务器有交互,服务器就会重新计时。
代码:
// 输出会话过期的时间
HttpSession session = request.getSession();
out.print("是否新的会话:" + session.isNew() + "<br/>");
out.print("会话的ID:" + session.getId() + "<br/>");
//修改会话过期的时间
session.setMaxInactiveInterval(10);
out.print("服务器会话过期的时间:" + session.getMaxInactiveInterval() + "秒");
结果:
方式二:
- 通过修改web.xml中配置,修改会话过期的时间
<!-- 修改会话过期的时间 -->
<session-config>
<!-- 单位是:分钟 -->
<session-timeout>5</session-timeout>
</session-config>
疑问:设置web.xml的会话配置,并且在代码中设置会话过期的时间,以哪个为准?
- 就近的原则,以代码中的为准(代码会把配置文件的覆盖了)
方式三:立刻失效
session.invalidate()
- 让会话立刻失效,一般用在注销或退出
案例
需求:用户登录的时候使用验证码进行验证
登录成功后将用户信息保存到会话域中,并且跳转到WelcomeServlet,然后在WeclcomeServlet中读取用户信息,显示欢迎信息。在WelcomeServlet上显示退出的链接,点退出,注销会话信息。
8.2 LoginServlet实现步骤:
1) 使用昨天的代码实现验证码的绘制
3) 用户登录的时候提交验证码的字符串
4) 比较表单提交的字符串是否与会话域中的字符串相等,如果相等则验证成功
5) 登录一次以后删除会话域中的验证码字符串
6) 登录成功以后保存用户的信息到会话域中,并且跳转到WelcomeServlet
8.3 WelcomeServlet的实现步骤:
1) 从会话域中取出用户信息并且显示
2) 判断用户是否正常登录,如果是非法用户则跳转到登录页面
3) 在页面上输出一个注销的连接,点注销跳转到LogoutServlet
8.4 LogoutServlet的实现步骤:
1) 让会话立刻过期
2) 显示您已经成功退出
Code
loginServlet:
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//设置编码问题
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
//获得打印流
PrintWriter writer = response.getWriter();
//获得会话对象
HttpSession session = request.getSession();
//获得会话域中的验证码的值
String sessionVcode=(String) session.getAttribute("vcode");
//删除验证码使得验证码只能使用一次
session.removeAttribute("vcode");
//获得表单提交的参数
String vcode =request.getParameter("vcode");
String username = request.getParameter("username");
String password = request.getParameter("password");
//获得业务层对象
UserService userService=new UserService();
//通过业务层的方法查找这用户名是否存在对象
User user = userService.getUser(username);
writer.print("<script>");
//先判断验证码是否正确
if(vcode.equalsIgnoreCase(sessionVcode)){
//判断找到的用户是否为空
if(user!=null){
System.out.println(user);
//判断用户名和密码是否正确
if(username.equals(user.getUsername())&&password.equals(user.getPassword())){
//先把用户的信息存在会话域中
session.setAttribute("user", user);
//然后跳转到登陆成功的页面
response.sendRedirect(request.getContextPath()+"/welcome");
}else{
//作出提示并跳转
writer.print("alert('密码不正确');");
writer.print("location.href='login.html'");
}
}else{
//作出提示并跳转
writer.print("alert('用户名密码不正确');");
writer.print("location.href='login.html'");
}
}else{
//作出提示并跳转
writer.print("alert('验证码不正确');");
writer.print("location.href='login.html'");
}
writer.print("</script>");
}
WelcomeServlet:
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//设置编码问题
response.setCharacterEncoding("utf-8");
response.setContentType("text/html");
//获得打印流
PrintWriter out = response.getWriter();
//获得会话对象
HttpSession session = request.getSession();
//通过会话域获得User对象
User user =(User) session.getAttribute("user");
//判断是否非法访问,
if(user==null){
//帮他跳转到用户登陆
response.sendRedirect(request.getContextPath()+"/login.html");
return;
}
//界面的显示
out.print("<h1>WelcomeServlet</h1><br/>");
out.print("<h2>欢迎你!"+user.getUsername()+"!</h2><br/>");
out.print("<a href='logout'>退出</a>");
out.close();
}
logoutServlet:
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//设置编码的问题
response.setCharacterEncoding("utf-8");
response.setContentType("text/html");
//获得打印流
PrintWriter out = response.getWriter();
//让用户的信息失效,注销
request.getSession().invalidate();
//界面显示
out.print("<h1>LogoutServlet</h1><br/>");
out.print("<a href='login.html'>返回登陆界面</a>");
out.close();
}
other
PicCodeServlet:
动态验证码:
package com.Servlet;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* 验证码
*
* @author NewBoy
*
*/
public class PicCodeServlet extends HttpServlet {
private Random ran = new Random();
// 1) 写一个方法随机获取颜色
private Color getColor() {
// 随机得到0~255之间整数
int r = ran.nextInt(256);
int g = ran.nextInt(256);
int b = ran.nextInt(256);
return new Color(r, g, b);
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int width = 90;
int height =30;
// 2) 创建缓存图片:指定宽width=90,高height=30
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 3) 获取画笔对象
Graphics graphics = img.getGraphics();
// 4) 设置画笔颜色
graphics.setColor(Color.WHITE);
//填充矩形区域
graphics.fillRect(0, 0, width, height);
// 5) 从字符数组中随机得到字符
//创建会话
HttpSession session = request.getSession();
StringBuilder sb=new StringBuilder();
char[] arr = { 'A', 'B', 'C', 'D', 'N', 'E', 'W', 'b', 'o', 'y', '1', '2', '3', '4' };
for (int i = 0; i < 4; i++) {
//随机得到一个下标
int index = ran.nextInt(arr.length);
char c = arr[index];
sb.append(c);
//画字符
// 6) 设置字体,大小为18,设置字的颜色随机
graphics.setColor(getColor());
//设置字体:大小,加粗,斜体
graphics.setFont(new Font(Font.DIALOG, Font.BOLD + Font.ITALIC, 18));
// 7) 将每个字符画到图片,位置:5+(i*20), 20
graphics.drawString(String.valueOf(c),5+(i*20), 20);
}
//得到验证码,放到会话域中
session.setAttribute("vcode",sb.toString());
System.out.println(sb.toString());
// 8) 画干扰线7条线,线的位置是随机的,x范围在width之中,y的范围在height之中。
for (int i = 0; i < 7; i++) {
int x1 = ran.nextInt(width);
int y1 = ran.nextInt(height);
int x2 = ran.nextInt(width);
int y2 = ran.nextInt(height);
//随机设置颜色
graphics.setColor(getColor());
graphics.drawLine(x1, y1, x2, y2);
}
// 9) 将缓存的图片输出到响应输出流中,参数:图片,格式,输出流
ImageIO.write(img, "png", response.getOutputStream());
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
login.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>会员登录</title>
<link rel="stylesheet" href="css/bootstrap.min.css" type="text/css" />
<script src="js/jquery-1.11.3.min.js" type="text/javascript"></script>
<script src="js/bootstrap.min.js" type="text/javascript"></script>
<!-- 引入自定义css文件 style.css -->
<link rel="stylesheet" href="css/style.css" type="text/css"/>
<style>
body{
margin-top:20px;
margin:0 auto;
}
.carousel-inner .item img{
width:100%;
height:300px;
}
.container .row div{
/* position:relative;
float:left; */
}
font {
color: #666;
font-size: 22px;
font-weight: normal;
padding-right:17px;
}
</style>
</head>
<script type="text/javascript">
$(function(){
$("#vcode").click(function(){
$(this).attr("src","vcode?t="+Math.random());
});
})
</script>
<body>
<!--
描述:菜单栏
-->
<div class="container-fluid">
<div class="col-md-4">
<img src="img/logo2.png" />
</div>
<div class="col-md-5">
<img src="img/header.png" />
</div>
<div class="col-md-3" style="padding-top:20px">
<ol class="list-inline">
<li><a href="login.htm">登录</a></li>
<li><a href="register.htm">注册</a></li>
<li><a href="cart.htm">购物车</a></li>
</ol>
</div>
</div>
<!--
描述:导航条
-->
<div class="container-fluid">
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">首页</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="#">手机数码<span class="sr-only">(current)</span></a></li>
<li><a href="#">电脑办公</a></li>
<li><a href="#">电脑办公</a></li>
<li><a href="#">电脑办公</a></li>
</ul>
<form class="navbar-form navbar-right" role="search">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
<!-- /.navbar-collapse -->
</div>
<!-- /.container-fluid -->
</nav>
</div>
<div class="container" style="width:100%;height:460px;background:#FF2C4C url('img/loginbg.jpg') no-repeat;">
<div class="row">
<div class="col-md-7">
<!--<img src="./img/login.jpg" width="500" height="330" alt="会员登录" title="会员登录">-->
</div>
<div class="col-md-5">
<div style="width:440px;border:1px solid #E7E7E7;padding:20px 0 20px 30px;border-radius:5px;margin-top:60px;background:#fff;">
<font>会员登录</font>USER LOGIN
<div> </div>
<form class="form-horizontal" action="login" method="post">
<div class="form-group">
<label for="username" class="col-sm-2 control-label">用户名</label>
<div class="col-sm-6">
<input type="text" class="form-control" id="username" placeholder="请输入用户名" name="username">
</div>
</div>
<div class="form-group">
<label for="inputPassword3" class="col-sm-2 control-label">密码</label>
<div class="col-sm-6">
<input type="password" class="form-control" id="inputPassword3" placeholder="请输入密码" name="password">
</div>
</div>
<div class="form-group">
<label for="inputPassword3" class="col-sm-2 control-label">验证码</label>
<div class="col-sm-3">
<input type="text" class="form-control" id="inputPassword3" placeholder="请输入验证码" name="vcode">
</div>
<div class="col-sm-3">
<img src="vcode" id="vcode" title="看不清" style="cursor:pointer"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label>
<input type="checkbox"> 自动登录
</label>
<label>
<input type="checkbox"> 记住用户名
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<input type="submit" width="100" value="登录" name="submit" border="0"
style="background: url('./img/login.gif') no-repeat scroll 0 0 rgba(0, 0, 0, 0);
height:35px;width:100px;color:white;">
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<div style="margin-top:50px;">
<img src="./img/footer.jpg" width="100%" height="78" alt="我们的优势" title="我们的优势" />
</div>
<div style="text-align: center;margin-top: 5px;">
<ul class="list-inline">
<li><a>关于我们</a></li>
<li><a>联系我们</a></li>
<li><a>招贤纳士</a></li>
<li><a>法律声明</a></li>
<li><a>友情链接</a></li>
<li><a target="_blank">支付方式</a></li>
<li><a target="_blank">配送方式</a></li>
<li><a>服务声明</a></li>
<li><a>广告声明</a></li>
</ul>
</div>
<div style="text-align: center;margin-top: 5px;margin-bottom:20px;">
Copyright © 2005-2016 传智商城 版权所有
</div>
</body></html>