用户管理系统
最后更新于:2022-04-01 09:42:27
# 用户管理系统
### 基本概述
该系统是一个简单的用户管理系统,目前实现的功能不是很多,但是可以扩展。其结构采用的是MVC模式。
### MVC模型示意图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf600ab430.jpg)
### 系统框架图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf600ccb78.jpg)
### 开发目录结构图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf600f1180.jpg)
### 注意事项:
数据库采用的是Oracle数据库,用户名,密码之类的在上图的dbinfo.properties文件下更改,使用其他数据库也是在该文件下更改驱动名称。
### SQL
~~~
create table users
(
id number primary key, --id
username varchar2(32) not null, --用户名
email varchar2(64) not null, --电子邮箱
grade number default 1, --等级 1->5 1为普通用户,5为管理员
passwd varchar2(32) not null --密码
);
--插入测试数据
insert into users values(1,'zhangsan','zhangsan@switch.com',1,'123456');
insert into users values(2,'lisi','lisi@switch.com',1,'123456');
insert into users values(3,'wangwu','wangwu@switch.com',1,'123456');
insert into users values(4,'zhaoliu','zhaoliu@switch.com',1,'123456');
insert into users values(5,'switch','switch@switch.com',5,'switch');
insert into users values(6,'AAA','AAA@switch.com',1,'123456');
insert into users values(7,'BBB','BBB@switch.com',1,'123456');
insert into users values(8,'CCC','CCC@switch.com',1,'123456');
insert into users values(9,'DDD','DDD@switch.com',1,'123456');
insert into users values(10,'EEE','EEE@switch.com',1,'123456');
insert into users values(11,'FFF','FFF@switch.com',1,'123456');
insert into users values(12,'GGG','GGG@switch.com',1,'123456');
insert into users values(13,'HHH','HHH@switch.com',1,'123456');
insert into users values(14,'AAA','AAA@switch.com',1,'123456');
insert into users values(15,'BBB','BBB@switch.com',1,'123456');
insert into users values(16,'CCC','CCC@switch.com',1,'123456');
insert into users values(17,'DDD','DDD@switch.com',1,'123456');
insert into users values(18,'EEE','EEE@switch.com',1,'123456');
insert into users values(19,'FFF','FFF@switch.com',1,'123456');
insert into users values(20,'GGG','GGG@switch.com',1,'123456');
insert into users values(21,'HHH','HHH@switch.com',1,'123456');
insert into users values(22,'HHH','HHH@switch.com',1,'123456');
--分页语句
select * from (select u.*,rownum rn from (select * from users order by id) u where rownum <= 6) where rn >=4;
--序列自增长
create sequence users_seq
start with 100
increment by 1
minvalue 100
nomaxvalue
nocycle
nocache;
~~~
源代码:[http://download.csdn.net/detail/q547550831/9391557](http://download.csdn.net/detail/q547550831/9391557)
导入MyEclipse就能用了。
----------参考《韩顺平.细说Servlet》
ServletContext
最后更新于:2022-04-01 09:42:25
# ServletContext
### 基本概述
servletContext接口是Servlet中最大的一个接口,呈现了web应用的Servlet视图。ServletContext实例是通过 getServletContext()方法获得的,由于HttpServlet继承GenericServlet的关系,GenericServlet类和HttpServlet类同时具有该方法。
每个应用都会有一个ServletContext对象与之关联,当容器分布在在多个虚拟机上时,web应用在所分布的每个虚拟机上都拥有一个ServletContext实例.缺省情况下,ServletContext不是分布式的,并且只存在于一个虚拟机上。
参考文档:[http://tomcat.apache.org/tomcat-5.5-doc/servletapi/index.html](http://tomcat.apache.org/tomcat-5.5-doc/servletapi/index.html)
### ServletContext原理图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf6006ef15.jpg)
PS:一个WEB服务器上所有的Servlet共享一个ServletComtext。
### 小结
1、ServletContext 是在服务器
2、ServletContext 是被所有客户端共享
3、ServletContext 是当web应用启动的时候,自动创建
4、ServletContext 当web应用关闭/tomcat关闭/对web应用reload 会造成servletContext销毁
5、ServletContext 与 Session、Request一样都能存入属性、取出属性,但是其作用域和生命周期是不同的
1、ServletContext作用域是整个WEB应用,生命周期是从服务器启动到关闭
2、Session作用域是对应的会话,生命周期是从会话创建到会话销毁
3、Request作用域是一次响应,生命周期是一次响应(服务器将HTTP响应发给浏览器)
#### 6、ServletContext能够通过以下几种方式使用
1、获取
this.getServletConfig().getServletContext();
this.getServletContext(); //两种效果一样,推荐下面这种
2、添加属性
this.getServletContext().setAttribute(String,Object);
3、取出属性
this.getServletContext().getAttribute(属性名);
4、移除属性 //注意:痛Session、Request一样,移除属性只能一个一个移除
this.getServletContext().removeAttribute(属性名);
### ServletContext应用
#### 1、获取WEB应用的初始化参数
~~~
<!-- 如果希望所有的servlet都可以访问该配置. -->
<context-param>
<param-name>name</param-name>
<param-value>scott</param-value>
</context-param>
~~~
如何获取
~~~
String val= this.getServletContext().getInitParameter("name");
~~~
#### 2、使用ServletContext实现跳转
~~~
//目前我们跳转到下一个页面
//1 response.sendRedirect("/web应用名/资源名");
//2 request.getRequestDispatcher("/资源名").forward(request, response);
/*
* 区别1. getRequestDispatcher 一个跳转发生在web服务器 sendRedirect发生在浏览器
* 2. 如果request.setAttribute("name","Switch") 希望下一个页面可以使用属性值,则使用 getRequestDispatcher
* 3. 如果session.setAttribute("name2","Switch2"), 希望下一个页面可以使用属性值,则两个方法均可使用,但是建议使用 getRequestDispatcher
* 4. 如果我们希望跳转到本web应用外的一个url,应使用sendRedirect
*/
//3.这种方法和2一样
this.getServletContext().getRequestDispatcher("/资源url").forward(request, response);
~~~
#### 3、读取文件,和获取文件全路径
~~~
//首先读取到文件
InputStream inputStream=this.getServletContext().getResourceAsStream("dbinfo.properties");
//创建Properties
Properties pp=new Properties();
pp.load(inputStream);
out.println("name="+pp.getProperty("username"));
//如果文件放在src目录下,应该使用类加载器来读取
//InputStream is=Servlet5.class.getClassLoader().getResourceAsStream("dbinfo.properties");
//获取文件全路径
//读取到一个文件的全路径
String path=this.getServletContext().getRealPath("/imgs/Sunset.jpg");
out.println("paht = "+path);
~~~
----------参考《韩顺平.细说Servlet》
简易购物车
最后更新于:2022-04-01 09:42:22
# 简易购物车
就是一个简单的购物车,还可以扩展。
实现原理:
用户在ShowBook页面购书,BuyBookCl进行业务逻辑处理之后,显示在ShowMyCart上。Book是图书信息类,DB是一个内存图书数据库,用来存放初始化图书信息。
使用技术:
1、JAVASE中的ArrayList,HashMap,LinkedHashMap
2、Session技术
3、Servlet技术
4、单例
~~~
package com.pc;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Switch
* 功能:显示图书
*/
public class ShowBook extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 字符编码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
out.println("<h1>欢迎购买</h1>");
// 取出DB
ArrayList<Book> db = DB.getBooks();
for(Book book : db){
out.println(book.getName() + "<a href='/MyCart/BuyBookCl?id="+ book.getId() + "&name=" + book.getName() + "&price=" + book.getPrice() + "'>点击购买</a><br/>");
}
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
~~~
package com.pc;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Switch
* 功能:处理购书信息
*/
public class BuyBookCl extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 字符编码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
// 接收用户购书信息
String bookname = request.getParameter("name");
String id = request.getParameter("id");
String price = request.getParameter("price");
// 从会话获取总价
Float totalprice = (Float) request.getSession().getAttribute("totalprice");
// 将总价加入会话中
if(totalprice == null){
request.getSession().setAttribute("totalprice", Float.parseFloat(price));
} else {
request.getSession().setAttribute("totalprice", totalprice + Float.parseFloat(price));
}
// 从session中取出mybooks
HashMap<String, Book> books = (HashMap<String, Book>) request.getSession().getAttribute("mybooks");
// 如果是第一次购物 books == 空
if(books == null){
// 创建集合对象
books = new LinkedHashMap<String, Book>();
// 创建book对象
Book book = new Book();
book.setId(id);
book.setName(bookname);
// 设置图书数量为1
book.setNum(1);
books.put(id, book);
// 将bookd加入session
request.getSession().setAttribute("mybooks", books);
} else {
// 检测集合中是否有该书
if(books.containsKey(id)){
// 表示数已被购买过
// 从集合中取出图书
Book book = books.get(id);
// 数量+1
book.setNum(book.getNum() + 1);
} else {
// 该图书未被购买过
Book book = new Book();
book.setId(id);
book.setName(bookname);
book.setNum(1);
books.put(id, book);
}
}
// 转发到显示购物车界面
request.getRequestDispatcher("/ShowMyCart").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
~~~
package com.pc;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Switch
* 功能:显示购物车
*/
public class ShowMyCart extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 字符编码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
// 从session中取出购买的书
HashMap<String, Book> books = (HashMap<String, Book>) request.getSession().getAttribute("mybooks");
// 测试
// System.out.println(books);
out.println("您的购物车有以下书籍:<br/>");
Iterator iterator = books.keySet().iterator();
while(iterator.hasNext()){
Book book = books.get(iterator.next());
out.println("书名为:" + book.getName() + " 数量为:" + book.getNum());
out.println("<br/>");
}
out.println("总价为:" + request.getSession().getAttribute("totalprice"));
out.println("<br/>");
out.println("<a href='/MyCart/ShowBook'>返回购物大厅</a>");
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
~~~
package com.pc;
/**
* @author Switch
* 功能:存储图书信息
* id------id号
* name----书名
* num-----数量
* price---价格
*/
public class Book {
private String id;
private String name;
private int num;
private float price;
// 设置器与获取器
public String getId() {
return id;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}
~~~
~~~
package com.pc;
import java.io.Serializable;
import java.util.ArrayList;
/**
*
* @author Switch
* 功能:模拟内存数据库,单例实现
*
*/
public final class DB implements Serializable{
private static ArrayList<Book> books = null;
private DB(){
}
// 静态代码块初始化图书信息
static{
books = new ArrayList<Book>();
Book book1 = new Book();
book1.setId("1");
book1.setName("Think in Java");
book1.setPrice(99);
books.add(book1);
Book book2 = new Book();
book2.setId("2");
book2.setName("Javascript权威指南");
book2.setPrice(139);
books.add(book2);
Book book3 = new Book();
book3.setId("3");
book3.setName("Head First Servlet & JSP");
book3.setPrice(129);
books.add(book3);
Book book4 = new Book();
book4.setId("4");
book4.setName("设计模式之禅");
book4.setPrice(89);
books.add(book4);
Book book5 = new Book();
book5.setId("5");
book5.setName("Java核心技术");
book5.setPrice(139);
books.add(book5);
}
// 返回图书集合
public static ArrayList<Book> getBooks() {
return books;
}
}
~~~
----------参考《韩顺平.细说Servlet》
过滤器Filter
最后更新于:2022-04-01 09:42:20
# 过滤器Filter
### 基本概述
Java中的Filter 并不是一个标准的Servlet ,它不能处理用户请求,也不能对客户端生成响应。 主要用于对HttpServletRequest 进行预处理,也可以对HttpServletResponse 进行后处理,是个典型的处理链。
参考文档:[http://tomcat.apache.org/tomcat-5.5-doc/servletapi/index.html](http://tomcat.apache.org/tomcat-5.5-doc/servletapi/index.html)
参考博客:[http://blog.csdn.net/sd0902/article/details/8395641](http://blog.csdn.net/sd0902/article/details/8395641)
### 开发过滤器的步骤
#### 1、创建
继承HttpServlet 同时实现Filter接口
默认filter不生效,需要配置.
~~~
<!-- 配置的一个filter -->
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.pc.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/*</url-pattern> /*表示对该WEB的所有网页都过滤
</filter-mapping>
~~~
#### 2、在filter的方法中添加业务逻辑
~~~
package com.pc.filter;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.pc.domain.User;
public class MyFilter1 extends HttpServlet implements Filter {
public void doGet(HttpServletRequest request, HttpServletResponse response)hrows ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
System.out.print("myfilter1...");
//获取session
HttpServletRequest httpServletRequest=(HttpServletRequest)request;
//看看请求的资源是什么
String uri=httpServletRequest.getRequestURI();
if(uri.startsWith("/UsersManager3/imgs")||uri.startsWith("/UsersManager3/Login")){
// 该过滤器放行,进入下一个过滤器
chain.doFilter(request, response);
}else{
HttpSession session=httpServletRequest.getSession();
User user=(User) session.getAttribute("loginuser");
if(user!=null){
//该用户合法,放行
chain.doFilter(request, response);
}else{
request.setAttribute("err", "请好好登陆");
httpServletRequest.getRequestDispatcher("/LoginServlet")
.forward(request, response);
}
}
}
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
~~~
### 过滤器链
过滤器链的概念很容易理解,就是在配置过滤器时,多个过滤器加载进内存中时,当使用过滤器之后调用chain.doFilter(request, response);WEB服务器会按配置顺序决定下一个调用的过滤器是什么。这就可以视为过滤器链。
----------参考《韩顺平.细说Servlet》
Servlet详解
最后更新于:2022-04-01 09:42:18
# Servlet详解
### 基本概述
Session在计算机中,尤其是在网络应用中,称为“会话控制”。在计算机专业术语中,Session是指一个终端用户与交互系统进行通信的时间间隔,通常指从注册进入系统到注销退出系统之间所经过的时间。具体到Web中的Session指的就是用户在浏览某个网站时,从进入网站到关闭这个网站所经过的这段时间,也就是用户浏览这个网站所花费的时间。因此从上述的定义中可以看到,Session实际上是一个特定的时间概念。
参考文档:[http://tomcat.apache.org/tomcat-5.5-doc/servletapi/index.html](http://tomcat.apache.org/tomcat-5.5-doc/servletapi/index.html)
### Session工作原理图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf6001a1b6.jpg)
Tomcat默认是30分钟。
Tomcat主目录的conf文件夹中的web.xml文件可以进行设置全局默认会话生命周期时间。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf600388ea.jpg)
### 3种设置session生命周期的方法
#### 1、tomcat/conf/web.xml
如上图所示,将数字进行更改则行,单位为分钟。
#### 2、在web应用下的web.xml
直接在<web-app></web-app>中加入如图所示代码则行。
#### 3、通过request.getSession().setMaxInactiveInterval(time)
time是以秒为单位的。time为正数表示用户未操作多少秒后会话失效,0为立即失效,负数代表永不失效。
PS:session的生命周期的时间是指用户未操作时间,也就是说当用户未操作多少秒后失效。而cookie的生命周期的时间指得是累积的时间,也就说无论用户访问否,只要累积过去了多少秒后就失效了。
案例:
~~~
package com.pc;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class Servlet12 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 字符编码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
// 访问session [当发现没用session时,就会自动创建session]
HttpSession session = request.getSession();
// 给该session放入属性,可以加入对象
String val = URLEncoder.encode("张三", "utf-8");
session.setAttribute("name", val);
session.setAttribute("age", 20);
// session的生命周期(默认30min,可以修改)
// time指的是等待时间,如果超过这个时间,则会自动释放该会话
// session.setMaxInactiveInterval(time);
out.println("创建session并放入属性");
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
~~~
package com.pc;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class Servlet13 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 字符编码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
// 获取Session
HttpSession session = request.getSession();
// 获取属性
String name = (String) session.getAttribute("name");
Integer age = (Integer) session.getAttribute("age");
// 删除name属性
//session.removeAttribute("name");
if (name != null && age != null) {
out.println(URLDecoder.decode(name, "utf-8") + " " + age);
}
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
### 小结
1、session存在于服务器的内存中
2、一个用户浏览器,独享一个session域对象
3、session中的属性的默认生命周期是30min ,你可以通过 web.xml来修改
4、session中可以存放多个属性
5、session 可以存放对象
6、如果 request.getSession().setAttribute(“name”,val) , 如果名字重复,则会替换该属性.
7、生命周期设置优先级顺序为setMaxInactiveInterval > web应用下的web.xml设置 > tomcat/conf/web.xml下的设置
8、1,2两种方法之所以不能是秒级的一个关键原因是因为太耗费资源,3能是秒级的原因是因为它是对单个Session进行监控。
9、session生命周期时间指得是用户未操作时间,当用户访问后,有从新计时,可以采取如下几种方式使session或者其中属性失效。
1、重启、reload应用、关机,session会完全失效。
2、通过request.getSession().invalidate()让session中所有属性失效。
3、通过request.getSession().removeAttribute()让session中某一属性失效、
### Session工作原理更深入的理解
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf6004e2e4.jpg)
PS:JSESSIONID是Session自动生成的用于唯一表示Session对象的一个ID号,通过该ID号服务器可以对每一个浏览器进行标识。
### JSESSION控制session销毁时间
当关闭浏览器之后,因为session默认返回的Cookie是会话级别的,所以即使服务器那端session并没有失效,再打开浏览器也无法使用之前的会话了。不过可以通过重设JSESSIONID这个Cookie来实现有效期持续到session生命周期完。
案例:
~~~
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession();
session.setAttribute("name", "张三");
out.println("创一个session并放入姓名属性");
//把该session id保存cookie,在id时,一定要按照规范命名,这里区分大小写
Cookie cookie = new Cookie("JSESSIONID", session.getId());
cookie.setMaxAge(60*30);
response.addCookie(cookie);
}
~~~
~~~
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
HttpSession httpSession = request.getSession();
String name = (String) httpSession.getAttribute("name");
out.println("name = "+name);
}
~~~
### Cookie禁用后使用Session的方法
cookie禁用后可以使用URL重写的方法,来实现Session。
#### 基本语法:
response.encodeRedirectURL(java.lang.String url)
用于对sendRedirect方法后的url地址进行重写
response.encodeURL(java.lang.String url)
用于对表单action和超链接的url地址进行重写
#### encodeURL (String url)方法的实现机制为:
先判断当前的 Web 组件是否启用 Session,如果没有启用 Session,直接返回参数 url,再判断客户端浏览器是否支持 Cookie,如果支持 Cookie,直接返回参数 url;如果不支持 Cookie,就在参数 url 中加入 Session ID 信息,然后返回修改后的 url。
### cookie与session的比较
#### 1、存在的位置
cookie:存在客户端的临时文件夹
session:存在服务器内存中,一个session域对象为一个用户浏览器服务
#### 2、安全性
cookie:是以明文的方式放在客户端的,安全性弱,可以通过(MD5)加密再存放。
session:是存放在服务器内存中,所有安全性好
#### 3、网络传输
cookie:属性值会传递信息给服务器
session:属性值不会给客户端
#### 4、生命周期
cookie的生命周期:是累计时间,即如果我们给cookie设置setMaxAge(30),则30秒后失效。
session的生命周期:是间隔时间,如我们设置session 20min,指在20min内,如果没有访问session,则session失效(session失效是指无法读取session属性),
在以下情况session也会失效
(1)关闭tomcat (2)reload web应用 (3)时间到 (4) 调用invalidate方法
#### 5、作用范围
cookie:能够被多个浏览器共享
session:只能一个浏览器使用
#### 6、使用原则
session:因为session会占用服务器的内存,因此不要向session中存放过多过大的对象,会影响性能。
cookie:不要将太多数据放置在cookie中,这样会使用大量带宽。
----------参考《韩顺平.细说Servlet》
Cookie入门
最后更新于:2022-04-01 09:42:15
# Cookie入门
### 基本概述
Cookie,有时也用其复数形式Cookies,指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)。Cookie也可以叫做浏览器缓存。
因为HTTP是无状态的协议,它不能保存用户状态,这时候往往会用到Cookie技术来对用户进行标识并进行一些特定的处理。服务器可以利用Cookies包含信息的任意性来筛选并经常性维护这些信息,以判断在HTTP传输中的状态。
参考文档:[http://tomcat.apache.org/tomcat-5.5-doc/servletapi/index.html](http://tomcat.apache.org/tomcat-5.5-doc/servletapi/index.html)
### Cookie原理图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5ffe7274.jpg)
案例:
~~~
package com.pc;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Switch
* 功能:设置Cookie
*/
public class Servlet8 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 字符编码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
// 创建Cookie (api)
Cookie cookie = new Cookie("Switch", "123456");
// 设置cookie的生命周期
cookie.setMaxAge(3600);
// 把cookie信息会写给浏览器
response.addCookie(cookie);
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
~~~
package com.pc;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* @author Switch
* 功能:获取Cookie
*
*/
public class Servlet9 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 字符编码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
// 获取客户端发过来的所有cookie
Cookie[] cookies = request.getCookies();
if (cookies != null) {
// 测试
// System.out.println(cookies.length);
for(Cookie c : cookies){
out.println(c.getName() + " " + c.getValue());
}
}
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
~~~
package com.pc;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Switch
* 功能:测试Cookie同名会发生什么情况
*/
public class Servlet10 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 字符编码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
// 创建Cookie (api)
Cookie cookie1 = new Cookie("Switch2", "123456");
// 设置cookie的生命周期
cookie1.setMaxAge(3600);
// 把cookie信息会写给浏览器
response.addCookie(cookie1);
// 同名会后面的会覆盖前面的Cookie
Cookie cookie2 = new Cookie("Switch2", "654321");
// 设置cookie的生命周期
cookie2.setMaxAge(3600);
// 把cookie信息会写给浏览器
response.addCookie(cookie2);
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
小结:
1、cookie是在服务器创建的
2、cookie是保存在浏览器缓存文件中的
3、cookie的生命周期是可设置的
cookie.setMaxAge(time); // time是以秒为单位的
如果不设置setMaxAge则当浏览器关闭时,该cookie就消亡。
4、cookie可以被多个浏览器共享
5、cookie是(名---值)对应关系
name和value都是String型的
如果设置Cookie,name相同,则后设置会覆盖前设置
6、一个web应用中可以保存多个cookie,并且会保存在浏览器缓存文件夹的同一个文件中
7、cookie存放方式是以明文的方式,所以为了安全,要进行加密。
### MD5加密算法
~~~
package com.pc;
import java.security.*;
import java.security.spec.*;
/**
* @author Switch
* 功能:MD5加密
*/
class MD5_test {
public final static String MD5(String s) {
char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f' };
try {
byte[] strTemp = s.getBytes();
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(strTemp);
byte[] md = mdTemp.digest();
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
return null;
}
}
public static void main(String[] args) {
System.out.print(MD5_test.MD5("Switch"));
}
}
~~~
PS:MD5是一种单向加密方式,其加密是不可逆转的,但是也可能存在破解方法,不过要一定的时间,所以建议采用MD5 64位加密或者是128位加密,该提供的方法只是32位加密方式。
使用Cookie保存用户重要信息时,比如密码、银行账号时,必须要进行加密传输存储。
案例:保存上次登录的时间
~~~
package com.pc;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Servlet11 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 字符编码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
// 用Cookie记录上次登录时间
boolean b = false;
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
// 获取name
String name = cookie.getName();
if ("lasttime".equals(name)) {
// 显示时间
out.println("上次登录时间是:" + cookie.getValue());
updateDate(response);
b = true;
break;
}
}
}
if (!b) {
out.println("这是您第一次登录");
updateDate(response);
}
out.flush();
out.close();
}
private void updateDate(HttpServletResponse response) {
// 更新时间
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
String nowDate = simpleDateFormat.format(new Date());
Cookie c = new Cookie("lasttime", nowDate);
// 7天有效期
c.setMaxAge(3600 * 24 * 7);
response.addCookie(c);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
### cookie生命周期
cookie默认的生命周期是会话级别的,也就是说浏览器一关闭cookie立即失效。可以通过setMaxAge(time)的方法设置生命周期。
<table><tbody><tr><td valign="top"><p>time </p></td><td valign="top"><p>解释</p></td></tr><tr><td valign="top"><p>正数 </p></td><td valign="top"><p>设置多少秒后失效</p></td></tr><tr><td valign="top"><p>0 </p></td><td valign="top"><p>删除该<span style="font-family:Calibri">cookie</span></p></td></tr><tr><td valign="top"><p>负数 </p></td><td valign="top"><p>设置该<span style="font-family:Calibri">cookie</span><span style="font-family:宋体">为会话级别</span></p></td></tr></tbody></table>
案例:
~~~
//先得到该cookie
Cookie cookies[]=request.getCookies();
for(Cookie cookie: cookies){
if(cookie.getName().equals("id")){
System.out.println("id");
//删除
cookie.setMaxAge(0);
//一定带上这句话,否则不能删除
response.addCookie(cookie);
}
}
~~~
PS:如果该web应用只有一个cookie ,则删除该cookie后,在浏览器的临时文件夹下没有该cookie文件,如果该web应用有多个cookie,则删除一个cookie后,文件还在,只是该cookie没有。
### cookie细节
1、一个浏览器最多能够存放300个cookie,每个web站点,最多只能占用20个cookie,而且一个cookie大小最大不能超过4k。
2、cookie存放中文,有可能会出现乱码的情况,这时可以采用如下方法解决
存放:
String val=java.net.URLEncoder.encode("张三","utf-8");
Cookie cookie=new Cookie("name",val);
取出:
String val=java.net.URLDecoder.decode(cookie.getValue(), "utf-8");
out.println("name ="+val);
----------参考《韩顺平.细说Servlet》
Servlet传递数据方式
最后更新于:2022-04-01 09:42:13
# Servlet传递数据方式
### 基本概述
Servlet传递数据的方式有很多,这里提供五种方式:
1、静态变量
2、HttpServletResponse的sendRedirect()方法
3、HttpServletRequest的getRequestDispatch()方法
4、HttpServletRequest的getSession()方法
5、HttpServletRequest的setAttribute()方法
### 静态变量
通过建立一个数据类来进行传递。
案例:
public class MyData{
public static String data; //通过使用该类来实现数据传递
}
### HttpServletResponse的sendRedirect()方法
sendRedirect()方法是让浏览器重定向到另一个链接。其内部原理是设置状态码为303,并设置相应的Location响应头。
基本语法:
response.sendRedirect("/Web应用名/资源名?uname="+username+"&pwd="+password);
response.sendRedirect(“servlet的地址?参数名=参数值&参数名=参数值...”);
参照值是String , 参数名应当使用 字母组合
在接受数据的Servlet中:
String 参数=request.getParameter(“参数名”);
#### 基本原理图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5ffafca2.jpg)
PS:使用重定向不能使用PrintWrite,ServletOutputStream这样的流。因为重定向已经将消息返回给浏览器,其数据流也就没必要使用了。
### HttpServletRequest的getRequestDispatch()方法
getRequestDispatch()方法是使WEB服务器从当前Servlet转发到当前应用下的另一个Servlet。
基本语法:
request.getRequestDispatcher(资源地址).forward(request,response);
资源地址:不需要项目名。因为它只能在WEB服务器内部转发。
#### 基本原理图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5ffcd019.jpg)
PS:getRequestDispatcher()请求转发可以一直转发下去,只要最终会处理并给服务器相应内容就行了。而且请求转发不会改变浏览器的URL,sendRedirect()会改变URL。
注意事项:
1、使用forward不能转发到该WEB应用外的URL
2、因为forward发生在文本服务器内,所以Servlet1、Servlet2等等,只要一直转发,使用的都是相同的request和response
### HttpServletRequest的getSession()方法
getSession()方法会获取一个会话,这个内容会在另一篇博客会话技术中详细说明。
基本语法:
1、放入session:request.getSession.setAttribute("loginUser",username);
2、取出session:request.getSession.getAttribute("loginUser");
PS:该方法可以传递对象
案例:
放入:
User user= new User();
user.setName(“zs”);
user.setPassWord(“123”);
request.getSession.setAttribute("userObj",userObj);
取出:
User user=(User)request.getSession.getAttribute(“userObj”);
### HttpServletRequest的setAttribute()方法
setAttribute()方法可以设置一个键值对,该键值对在该request的有效期内都可以使用。相应的还有removeAttribute()注销键值对的方法。该方法经常和getRequestDispatch()一起使用。
基本语法:
setAttribute(name, value);
PS:request的Attribute在一次请求中有效。一次请求:没有将响应消息返回给浏览器就视为一次请求。
### 比较sendRedirect()和forward(request,response)
1、sendRedirect()重定向,forward()转发
2、实际发生的位置不一样
sendRedirect 发生在浏览器
forward 发生在web服务器
3、使用用法不一样
request.getRequestDispatcher(“/资源URI”).forward(request,response)
response.sendRedirect(“/web应用/资源URI”);
4、能够去URL范围不一样
sendRedirect可以去任意URL
forward 只能去当前的WEB应用的资源
----------参考《韩顺平.细说Servlet》
HttpServletRequest说明
最后更新于:2022-04-01 09:42:11
# HttpServletRequest说明
### 基本概述
该对象是有Web服务器创建的,每一次请求都会创建一次。其作用是将HTTP请求封装成一个类,供Servlet处理。
参考文档:[http://tomcat.apache.org/tomcat-5.5-doc/servletapi/index.html](http://tomcat.apache.org/tomcat-5.5-doc/servletapi/index.html)
### 常用方法
getRequestURL方法返回客户端发出请求时的完整URL。
getRequestURI方法返回请求行中的资源名部分。
getQueryString 方法返回请求行中的参数部分(参数名+值)。
该函数可以获取请求部分的数据 比如
http://localhost/web名?username=abc&pwd=123
request.getQueryString(); 就会得到 username=abc&pwd=123
getRemoteAddr方法返回发出请求的客户机的IP地址
getRemoteHost方法返回发出请求的客户机的完整主机名
getRemotePort方法返回客户机所使用的网络端口号
客户机的端口号是随机选择的,web服务器的端口号是一定的
getLocalPort方法返回web服务器所使用的网络端口号
getLocalAddr方法返回WEB服务器的IP地址。
getLocalName方法返回WEB服务器的主机名
getMothod方法返回浏览器的提交方式
### URL(统一资源定位符)和URI(统一资源标识符)的区别
案例:
URL=http://localhost:8080/web1/Servlet7 完整的请求
Uri=/web1/Servlet7 web应用的名称+资源的名称
### 获取用户提交的内容(通过表单)
案例:
~~~
package com.pc;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInfoForm extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("<form action='/servletPro3/RegisterCl' method='post'><br/>");
out.println("<input type='hidden' value='abc' name='hidden1'/>");
out.println("用户名:<input type='text' name='username'/><br/>");
out.println("密 码:<input type='password' name='pwd'/><br/>");
out.println("性 别:<input type='radio' name='sex' value='男'/>男 <input type='radio' name='sex' value='女'/>女<br/>");
out.println("你的爱好:<input type='checkbox' name='hobby' value='音乐'>音乐 <input type='checkbox' name='hobby' value='体育'>体育 <input type='checkbox' name='hobby' value=\"旅游\">旅游<br/>");
out.println("所在城市:<select name='city'><option value='bj'>北京</option><option value='hn'>湖南</option></select><br/>");
out.println("你的介绍:<textarea cols='20' rows='10' name='intro' >请输入介绍..</textarea><br/>");
out.println("提交照片:<input type='file' name='photo'><br/>");
//什么时候使用hidden传输数据 1.不希望用户看到该数据 2. 不希望影响界面,同时使用该数据
out.println("<input type='submit' value='提交信息'/>");
out.println("</form>");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
接受信息的Servlet:
~~~
package com.pc;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RegisterCl extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
String u=request.getParameter("username");
String p=request.getParameter("pwd");
String sex=request.getParameter("sex");
//如果接受复选框的内容,则使用getparameterValues
String [] hobbies=request.getParameterValues("hobby");
String city=request.getParameter("city");
String intro=request.getParameter("intro");
String hidden1=request.getParameter("hidden1");
out.println("用户名="+u+"<br/>");
out.println("密 码="+p+"<br/>");
out.println("性 别="+sex+"<br/>");
if(hobbies!=null){
for(int i=0;i<hobbies.length;i++){
out.println("爱好:"+hobbies[i]);
}
}else{
out.println("无爱好");
}
out.println("<br/>所在城市:"+city);
out.println("<br/>个人介绍:"+intro);
out.println("<br/>隐藏数据:"+hidden1);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
----------参考《韩顺平.细说Servlet》
Servlet中文乱码处理
最后更新于:2022-04-01 09:42:08
# Servlet中文乱码处理
### 发生中文乱码的原因
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5ff9430f.jpg)
### 发生中文乱码的各种情况
#### 1、表单form
##### (1)post
在服务器端设置成浏览器端的编码方式。
解决方法: request.setCharacterEncoding("utf-8"); //gbk gb2312 big5
##### (2)get
写一个工具类:
~~~
package com.pc.utils;
public class MyTools {
public static String getNewString(String str) {
String newString="";
try {
// 把iso-8859-1 转换成 utf-8
newString=new String(str.getBytes("iso-8859-1"),"utf-8");
} catch (Exception e) {
e.printStackTrace();
}
return newString;
}
}
~~~
#### 2、超链接
<a href=”http://www.sohu.com?name=函数后”>测试</a>
PS:该方法和get处理方法一样
#### 3 、sendRedirect() 发生乱码
response.sendRedirect(“servlet地址?username=张三”);
PS:重定向默认是get方法,所以处理方法参照get。
重定向产生乱码的原因:
重定向的原理是Web服务器告知浏览器,要浏览器访问另一个地址,这样HttpServletResponse和HttpServletRequest对象都是不同的了,所以需要到跳转的地址再次设置才行。
#### 4、返回浏览器显示乱码
在服务端是中文,在response的时候,也要考虑浏览器显示是否正确,一般通过使用:
response.setContentType(“text/html;charset=utf-8”);
#### 5、下载提示框中文乱码
下载文件的时候,可能提示框是中文乱码
String temp=java.net.URLEncoder.encode("演员.mp3","utf-8");
response.setHeader("Content-Disposition","attachment; filename="+temp);
PS:应当尽量使用post 方式提交,因为post方式提交处理该问题简单,而get方式就有点麻烦了。
----------参考《韩顺平.细说Servlet》
HttpServletResponse说明
最后更新于:2022-04-01 09:42:06
# HttpServletResponse说明
### 基本概述
HttpServletResponse是用于将Servlet处理好的内容发送给浏览器的类,服务器通过对HttpServletResponse对象中的内容进行截取、拼接就能获得一个完整的HTTP响应信息。
参考文档:[http://tomcat.apache.org/tomcat-5.5-doc/servletapi/index.html](http://tomcat.apache.org/tomcat-5.5-doc/servletapi/index.html)
### 常用方法
public void addHeader(String name,String value) //添加一个消息头到HttpServletResponse对象中去。
public void setHeader(String name,String value) //重设一个消息头,其与addHeader的区别是,add是添加(重复也行),set表示的是,如果有该消息头就覆盖它,没有就创建它
public void setStatus(int sc) //设置响应消息的状态码,具体可以参照我的另一篇博客HTTP协议入门
public void sendRedirect(String location) throws java.io.IOException // 这个方法在与request的getRequestDispatch()比较时,会探讨
public ServletOutputStream getOutputStream() throws java.io.IOException //得到一个二进制输出流,可以回送任意格式数据数据
public java.io.PrintWriter getWriter() throws java.io.IOException //得到一个字符输出流,可以回送字符数据
### getWriter()和getOutputStream()的区别
getWriter() 用于向客户机回送字符数据
getOutputStream() 返回的对象,可以回送字符数据,也可以回送字节数据(二进制数据)
OutputStream os=response.getOutputStream();
os.write("hello,world".getBytes());
PS:通过该方法也能用getOutputStream()回送字符数据
#### 如何选择
如果是回送字符数据,则使用 PrintWriter对象 ,效率高
如果是回送字节数据(binary date) ,则只能使用 OutputStream
#### 注意事项
PrintWriter,OutputStream 这两个流不能同时使用
比如:
OutputStream os=response.getOutputStream();
os.write("hello,world".getBytes());
PrintWriter out=response.getWriter();
out.println("abc");
会报错:
java.lang.IllegalStateException: getOutputStream() has already been called for this response
#### 不能同时使用PrintWriter和OutputStream的原因
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5ff7730b.jpg)
结论:Web服务器在完成一次service之后会自动关闭流,并销毁当前的request和response对象,故无法同时使用两个流。
案例:
~~~
package com.pc;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Servlet7 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
// 演示下载文件
response.setHeader("Content-Disposition", "attachment; filename=EVO_120G.jpg");
// 打开文件
// 1.获取到要下载文件的全路径
String path = this.getServletContext().getRealPath("/EVO_120G.jpg");
// 测试
System.out.println("path=" + path);
// 2.创建文件输入流
FileInputStream fis = new FileInputStream(new File(path));
// 做一个缓冲字符数组
byte buff[] = new byte[1024];
int length = 0;
// 3.指向response的输出流
OutputStream os = response.getOutputStream();
// 4.循环读出
// length表示每次实际读入的字节数
while((length = fis.read(buff)) != -1){
os.write(buff, 0, length);
}
// 关闭
os.close();
fis.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
----------参考《韩顺平.细说Servlet》
HTTP协议入门——1.1版本
最后更新于:2022-04-01 09:42:04
# HTTP协议入门——1.1版本
### 基本概述
超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。
HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传输协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。
HTTP是客户端浏览器或其他程序与Web服务器之间的应用层通信协议。在Internet上的Web服务器上存放的都是超文本信息,客户机需要通过HTTP协议传输所要访问的超文本信息。HTTP包含命令和传输信息,不仅可用于Web访问,也可以用于其他因特网/内联网应用系统之间的通信,从而实现各类应用资源超媒体访问的集成。
### 长连接和短连接的区别
解释1
所谓长连接指建立SOCKET连接后不管是否使用都保持连接,但安全性较差,
所谓短连接指建立SOCKET连接后发送后接收完数据后马上断开连接,一般银行都使用短连接
解释2
长连接就是指在基于tcp的通讯中,一直保持连接,不管当前是否发送或者接收数据。
而短连接就是只有在有数据传输的时候才进行连接,客户-服务器通信/传输数据完毕就关闭连接。
解释3
长连接和短连接这个概念好像只有移动的CMPP协议中提到了,其他的地方没有看到过。
通信方式
各网元之间共有两种连接方式:长连接和短连接。所谓长连接,指在一个TCP连接上可以连续发送多个数据包,在TCP连接保持期间,如果没有数据包发送,需要双方发检测包以维持此连接。短连接是指通信双方有数据交互时,就建立一个TCP连接,数据发送完成后,则断开此TCP连接,即每次TCP连接只完成一对 CMPP消息的发送。
现阶段,要求ISMG之间必须采用长连接的通信方式,建议SP与ISMG之间采用长连接的通信方式。
解释4
短连接:比如http的,只是连接、请求、关闭,过程时间较短,服务器若是一段时间内没有收到请求即可关闭连接。
长连接:有些服务需要长时间连接到服务器,比如CMPP,一般需要自己做在线维持。
参考文章:[http://blog.csdn.net/shine0181/article/details/7799754](http://blog.csdn.net/shine0181/article/details/7799754)
### HTTP请求部分
#### 基本结构
GET /q547550831?viewmode=contents HTTP/1.1 [请求行]
Host: blog.csdn.net [消息头] 消息名:内容
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36
Referer: http://blog.csdn.net/q547550831?viewmode=contents
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
PS:这是我博客主页的请求头,但是这并不代表每个网页的请求头都是这一样的。
#### 请求方式
请求方式有:
POST,GET,HEAD,OPTIONS,DELETE,TRACE,PUT,CONNECT等
参考文档:[http://tools.jb51.net/table/http_request_method](http://tools.jb51.net/table/http_request_method)
常用的有:POST和GET
#### 请求消息头
Host: blog.csdn.net [主机名]
Connection: keep-alive [连接状态:保持连接]
Cache-Control: max-age=0 [指定请求和响应遵循的缓存机制:查看是否有修改并选择更新否]
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 [可接受的格式]
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36 [浏览器内核]
Referer: [http://blog.csdn.net/q547550831?viewmode=contents](http://blog.csdn.net/q547550831?viewmode=contents) [从哪个网页跳转到这个网页来的,可以用来防盗链]
Accept-Encoding: gzip, deflate, sdch [可接收的压缩格式]
Accept-Language: zh-CN,zh;q=0.8 [浏览器支持的语言]
PS:请求是指浏览器发出向服务器发出,所以这些信息都是浏览器的信息。请求头远远不止这几种,可以参考该文档:[http://tools.jb51.net/table/http_header](http://tools.jb51.net/table/http_header)
案例:防止盗链
~~~
package com.pc;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Servlet6 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
out.println("<a href='http://127.0.0.1:8080/servlet1/Servlet5'>连接到Servlet5</a>");
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
~~~
package com.pc;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Servlet5 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
// 通过request对象来获取http请求信息
// 取出Host
String host = request.getHeader("Host");
out.println("host=" + host);
// 限制用户
// 获取用户浏览器的Referer
// referer可以防止盗链,通过判断链接来至哪里
String referer = request.getHeader("Referer");
if(referer == null || !referer.startsWith("http://127.0.0.1:8080/servlet1")){
out.println("非法盗链");
} else {
out.println("referer=" + referer);
}
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 一般开发人员习惯把doGet()和doPost()合二为一
this.doGet(request, response);
}
public void init() throws ServletException {
// Put your code here
}
}
~~~
PS:该案例中只能允许http://127.0.0.1:8080/servlet1开头的网址进行访问Servlet5
### HTTP响应部分
#### 基本结构
HTTP/1.1 200 OK [状态行]
Server: openresty [消息名] 消息名:内容
Date: Fri, 01 Jan 2016 08:11:04 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
Cache-Control: private
Set-Cookie: uuid=5cad65d6-7a99-4b15-a6e6-5c50e584ca77; expires=Sat, 02-Jan-2016 08:13:49 GMT; path=/
Set-Cookie: ViewMode=contents; path=/
Content-Encoding: gzip
**--------------这是一个空行**
**消息体**
#### 响应状态码
响应状态码分别为1,2,3,4,5开头的三位数字
<table><tbody><tr><td valign="center"><p style="text-align:left">1** </p></td><td valign="center"><p style="text-align:left">信息,服务器收到请求,需要请求者继续执行操作</p></td></tr><tr><td valign="center"><p style="text-align:left">2** </p></td><td valign="center"><p style="text-align:left">成功,操作被成功接收并处理</p></td></tr><tr><td valign="center"><p style="text-align:left">3** </p></td><td valign="center"><p style="text-align:left">重定向,需要进一步的操作以完成请求</p></td></tr><tr><td valign="center"><p style="text-align:left">4** </p></td><td valign="center"><p style="text-align:left">客户端错误,请求包含语法错误或无法完成请求</p></td></tr><tr><td valign="center"><p style="text-align:left">5** </p></td><td valign="center"><p style="text-align:left">服务器错误,服务器在处理请求的过程中发生了错误</p></td></tr></tbody></table>
PS:常见的有200(成功),303(重定向),400(Not Found),500(服务器内部错误)
可以参考该文档:[http://tools.jb51.net/table/http_status_code](http://tools.jb51.net/table/http_status_code)
#### 响应消息头
Server: openresty [服务器名称]
Date: Fri, 01 Jan 2016 08:11:04 GMT [原始服务器消息发出的时间]
Content-Type: text/html; charset=utf-8 [返回内容的MIME类型]
Transfer-Encoding: chunked [文件传输编码]
Connection: keep-alive [连接状态:保持连接]
Vary: Accept-Encoding [告诉下游代理是使用缓存响应还是从原始服务器请求]
Cache-Control: private [告诉所有的缓存机制是否可以缓存及哪种类型]
Set-Cookie: uuid=********; expires=Sat, 02-Jan-2016 08:13:49 GMT; path=/ [设置Http Cookie]
Set-Cookie: ViewMode=contents; path=/ [设置Http Cookie]
Content-Encoding: gzip [web服务器支持的返回内容压缩编码类型]
PS:可以参考该文档[http://tools.jb51.net/table/http_header](http://tools.jb51.net/table/http_header)
### 缓存机制
浏览器默认情况下,会缓存所访问的页面,这样会出现一个问题:如果用户习惯把光标停留在地址栏,然后回车来取页面,就会默认调用cache中取数据。
案例1、有些网站要求及时性很高,因此要求不缓存页面。
//指定该页面不缓存 Ie
response.setDateHeader("Expires", -1);【针对IE浏览器设置不缓存】
//为了保证兼容性.
response.setHeader("Cache-Control", "no-cache");【针对火狐浏览器等】
response.setHeader("Pragma", "no-cache");【其他浏览器】
案例2、有些网站要求网页缓存一定时间,比如缓存一个小时
response.setDateHeader("Expires", System.currentTimeMillis()+3600*1000); //后面一个参数表示设置的缓存保持时间,-1表示永远不缓存
### Content-Type消息头
Content-Type,内容类型,一般是指网页中存在的Content-Type,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件
PS:其作用就是告诉浏览器,该服务器返回的网页中消息体是什么格式的,该以什么编码格式来读取这个网页。
因为该类型很多,故给出参考文档,以备后用:[http://tools.jb51.net/table/http_content_type](http://tools.jb51.net/table/http_content_type)
案例1:定时刷新Refresh的使用
response.setHeader("Refresh", "5;url=/servletPro/Servlet2"); // 5秒后刷新并跳转到url后的链接。通过这个可以实现页面定时刷新。
案例2:文件下载
~~~
package com.pc;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Servlet7 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
// 演示下载文件
response.setHeader("Content-Disposition", "attachment; filename=EVO_120G.jpg");
// 打开文件
// 1.获取到要下载文件的全路径
String path = this.getServletContext().getRealPath("/EVO_120G.jpg");
// 测试
System.out.println("path=" + path);
// 2.创建文件输入流
FileInputStream fis = new FileInputStream(new File(path));
// 做一个缓冲字符数组
byte buff[] = new byte[1024];
int length = 0;
// 3.指向response的输出流
OutputStream os = response.getOutputStream();
// 4.循环读出
// length表示每次实际读入的字节数
while((length = fis.read(buff)) != -1){
os.write(buff, 0, length);
}
// 关闭
os.close();
fis.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
----------参考《韩顺平.细说Servlet》
Servlet入门
最后更新于:2022-04-01 09:42:02
# Servlet入门
### 基本概述
Servlet(Server Applet),全称Java Servlet,未有中文译文。是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。
Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
PS:学习Servlet是学习JSP的基础,故很重要。
### Servlet在网络中的位置
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5ff00173.jpg)
### Servlet的生命周期
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5ff2ad54.jpg)
1、WEB服务器(Tomcat)首先会找到该Servlet并装载该Servlet
2、WEB服务器(Tomcat)会创建该Servlet的实例
3、WEB服务器(Tomcat)会调用实例对象的init()方法
4、WEB服务器(Tomcat)创建一个封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用service()方法并将请求对象和响应对象作为参数传递进去。(实现是通过多线程技术)
5、WEB服务器在某种情况,停止对该Servlet支持,Servlet引擎将卸载该Servlet,在卸载之前会调用Servlet的destroy()方法进行销毁
### 手工开发Servlet的方式
1、在Tomcat主目录的webapps文件夹下建立一个web应用web1
2、在web1下建立文件夹WEB-INF,在该文件夹中建立web.xml [web.xml可以从 ROOT/WEB-INF/web.xml拷贝]
3、在WEB-INF目录下建立classes目录(Servlet在该目录下开发),建立lib目录
4、在classes目录下开发Servlet
5、在web.xml中配置web.xml
6、编译Servlet文件(编译时需要将servlet-api.jar包加入环境变量classpath中,该jar包在Tomcat主目录的lib文件夹下)
7、运行Tomcat
8、访问Servlet
### 开发Servlet的三种方法
#### 1、实现Servlet接口
~~~
/**
使用实现Servlet接口的方式开发一个Servlet
要求:显示当前时间
*/
package com.pc;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class Servlet2 implements Servlet{
// 该方法用于初始化Servlet,就是把该Servlet装载入内存,该方法只会被调用一次
public void init(ServletConfig config){
}
// 得到ServletConfig对象
public ServletConfig getServletConfig(){
return null;
}
// 该方法是服务方法,业务逻辑代码写在这
// 该方法每次都会被调用
public void service(ServletRequest req, ServletResponse res) throws ServletException, java.io.IOException{
// 在控制台输出
System.out.println("hello world:" + new java.util.Date().toString());
// 在浏览器返回
res.getWriter().println("hello world:" + new java.util.Date().toLocaleString());
}
// 该方法得到Servlet配置信息
public java.lang.String getServletInfo(){
return null;
}
// 销毁该Servlet,从内存中清除,该方法只会被调用一次
public void destroy(){
}
}
~~~
PS:不仅要写Servlet文件,还要在web.xml中添加配置信息,配置信息格式如下:
~~~
<!-- servlet部署到web.xml文件,该部署配置可以从examples下拷贝 -->
<servlet>
<!--servlet-name 该名字可以自定义,但是默认就使用servlet的名字 -->
<servlet-name>Servlet2</servlet-name>
<!--servlet-class要指明该servlet放在那个包下的 -->
<servlet-class>com.pc.Servlet2</servlet-class>
</servlet>
<!-- servlet的映射 -->
<servlet-mapping>
<!-- 这个servlet-name要和上面的servlet-name名字一样,这样才能匹配的上 -->
<servlet-name>Servlet2</servlet-name>
<!-- url-pattern 这是访问该servlet的资源部分 默认命名规范:就是该servlet的名字-->
<url-pattern>/Servlet2</url-pattern>
</servlet-mapping>
~~~
PS:
1、在classes文件夹下编译(当然Servlet文件也应该在这里)
javac -encoding UTF-8 -d . Servlet文件名.java
2、不重启更新web应用
首先,在Tomcat主目录的conf文件夹中找到tomcat-users.xml文件,打开它,并在<tomcat-user></tomcat-user>标签中添加如下语句
~~~
<tomcat-users>
<role rolename="manager-gui"/>
<user username="tomcat" password="s3cret" roles="manager-gui"/>
</tomcat-users>
~~~
然后,在localhost:8080主界面点击,进入manager界面,找到该应用,点击reload按钮即可。
#### 2、继承GenericServlet类
~~~
/**
使用继承GenericServlet的方式开发一个Servlet
*/
package com.pc;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class Servlet3 extends GenericServlet{
// 该方法是服务方法,业务逻辑代码写在这
// 该方法每次都会被调用
public void service(ServletRequest req,ServletResponse res) throws ServletException,IOException{
res.getWriter().println("hellow,world, GenericServle.");
}
}
~~~
PS:不仅要写Servlet文件,还要在web.xml中添加配置信息,配置信息格式如下:
~~~
<servlet>
<servlet-name>Servlet3</servlet-name>
<servlet-class>com.pc.Servlet3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet3</servlet-name>
<url-pattern>/Servlet3</url-pattern>
</servlet-mapping>
~~~
#### 3、继承HttpServlet类
~~~
/**
使用继承HttpServlet的方式开发一个Servlet
要求:显示当前时间
*/
package com.pc;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class Servlet4 extends HttpServlet{
// 在HttpServlet中,设计者分别提供了对Post提交和Get提交的处理,默认是get提交
// doGet().doPost()底层也是调用service方法
// 处理Get请求
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException{
resp.getWriter().println("doGet()");
}
// 处理Post请求
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
resp.getWriter().println("doPost()");
}
}
~~~
PS:不仅要写Servlet文件,还要在web.xml中添加配置信息,配置信息格式如下:
~~~
<servlet>
<servlet-name>Servlet4</servlet-name>
<servlet-class>com.pc.Servlet4</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet4</servlet-name>
<url-pattern>/Servlet4</url-pattern>
</servlet-mapping>
~~~
### 使用MyEclipse集成开发环境IDE来开发Web应用
PS:具体的配置步骤可以参考搜索引擎。
#### MyEclipse的开发目录结构
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5ff553e8.jpg)
### Servlet细节问题
#### 1、一个已经注册的Servlet可以被多次映射
~~~
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<!-- servlet的注册名 -->
<servlet-name>MyServlet1</servlet-name>
<!-- servlet类的全路径(包名+类名) -->
<servlet-class>com.web1.servlet.MyServlet1</servlet-class>
</servlet>
<!-- 对一个已经注册的servlet的映射 -->
<servlet-mapping>
<!-- servelt的注册名 -->
<servlet-name>MyServlet1</servlet-name>
<!-- servlet的访问路径 -->
<url-pattern>/MyServlet1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MyServlet1</servlet-name>
<url-pattern>/abc</url-pattern>
</servlet-mapping>
~~~
#### 2、当映射一个Servlet时,可以多层映射
~~~
<url-pattern>/servlet/index.html</url-pattern>
~~~
#### 3、在Servlet使用通配符映射到URL
有两种格式:
第一种格式 *.扩展名 比如 *.do *.ss
第二种格式 以 / 开头 同时以 /* 结尾 比如 /* /news/*
通配符案例:
Servlet1 映射到 /abc/*
Servlet2 映射到 /*
Servlet3 映射到 /abc
Servlet4 映射到 *.do
问题:
1、当请求URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应
Servlet引擎将调用Servlet1。
2、当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应
Servlet引擎将调用Servlet3。
3、当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet1。
4、当请求URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet2。
5、当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet2。
在匹配的时候,要参考的标准:
1、看谁的匹配度高,谁就被选择
2、*.do 的优先级最低
#### 4、servlet中的<load-on-startup>配置
当需要在网站启动时,初始化一些资源时可以配置<load-on-startup>
~~~
<servlet>
<load-on-startup>1</load-on-startup>
</servlet>
~~~
PS:在servlet中如此配置就行,中间的数是整数,越小优先级越高。
配置好了之后,在网站启动时就会调用该Servlet的init()方法,所以可以在该方法中进行需要的初始化步骤,比如定时刷新,建立内存表之类的等等。
### ServletConfig对象
该对象主要用于读取 servlet的配置信息.
案例:
~~~
<servlet>
<servlet-name>ServletConfigTest</servlet-name>
<servlet-class>com.web1.servlet.ServletConfigTest</servlet-class>
<!-- 这里可以给servlet配置信息,这里配置的信息,只能被该servlet 读取 -->
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</servlet>
~~~
如何使用:在Servlet使用如下语句
~~~
String encoding = this.getServletConfig().getInitParameter("encoding");
~~~
补充说明:这种配置参数的方式,只能被某个Servlet独立使用.如希望让所有的Servlet都去读取某个参数,这样配置:
~~~
<!-- 如果这里配置参数,可被所有servlet读取 -->
<context-param>
<param-name></param-name>
<param-value></param-value>
</context-param>
~~~
读取所有的参数,可以使用如下方法:
~~~
Enumeration<String> names=this.getServletConfig().getInitParameterNames();
while(names.hasMoreElements()){
String name=names.nextElement();
System.out.println(name);
System.out.println(this.getServletConfig().getInitParameter(name));
}
~~~
### 注意事项:
1、Servlet类是单例模式的,所以要注意线程同步情况。
2、Servlet的service()方法,在每次响应时都会调用一次。
3、Servlet的init()初始化方法,destroy()销毁方法只会被调用一次。
4、Servlet的service()方法,会根据客户端的请求方法来决定调用对应的doXXX()方法。
5、不要重写构造方法,因为所继承的HttpServlet及其父类都已经对构造方法进行了某些初始化,当不了解这些系统自带的初始化,然后盲目使用构造方法,可能导致Servlet无法创建实例。
6、不要重写service方法(在继承HttpServlet的情况下),因为其内部有判别客户端请求方法的逻辑和一些其他逻辑。
7、必须重写doPost()或者是doGet()方法中的一个。
8、当想用一种逻辑去处理Get和Post请求,可以采用委托机制,在doPost方法内加入this.doGet(request, response); 或者在doGet方法中加入this.doPost(request, response);
9、继承HttpServlet开发Servlet是最常用的方法。
10、get提交和post提交的区别
10.1、从安全的角度看,get < post,因为get会把提交的信息显示到地址栏。
10.2、从提交内容大小看, get < post, get一般不要大于2k,post理论无限制,但是在实际开发中,建议不要大于64k
10.3、从速度看,get > post,因为get仅仅只是获取数据而已
11、Servlet的映射的后缀名不一定代表它就真的是那格式的文件。
----------参考《韩顺平.细说Servlet》
Tomcat容器入门介绍
最后更新于:2022-04-01 09:41:59
# Tomcat容器入门介绍
### Tomcat环境配置
PS:JDK的安装这里就不讲了,找到安装包直接下一步下一步就行了。
#### 1、配置JDK
在Windows10下,找到环境变量
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5fd22dc6.jpg)
在环境变量中添加JDK主目录
格式为:JAVA_HOME= 指向你的jdk的主目录(并不是bin文件目录)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5fd465be.jpg)
在环境变量中添加路径
格式为:path = %JAVA_HOME%\bin;
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5fd577f6.jpg)
在环境变量中添加classpath
格式为:classpath: .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5fd7305d.jpg)
至此,JDK就配置完了。
PS:如果在不配置JAVAHOME的前提下可以用如下方法启动tomcat
在startup.bat的第25行中添加set JAVA_HOME=JKD路径
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5fd877ce.jpg)
#### 2、启动tomcat
到 tomcat 主目录下的bin/startup.bat点击启动
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5fda8d88.jpg)
#### 3、验证是否安装成功
在浏览器中输入http://127.0.0.1:8080(8080是默认端口,如果该端口被占用需要到主目录/conf/server.xml中改端口号)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5fdcb568.jpg)
出现这个界面,就表示tomcat已经配置成功了。
### Tomcat配置异常及其解决
#### 1、JAVA_HOME 配置错误,或者没有配置
这时候,可以按照上面的步骤在来一次,在命令行中输入java -version,如果显示
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5fde2f31.jpg)
就表示成功了。
#### 2、如果你的机器已经占有了8080 端口,则无法启动
解决方法
(1) 你可以8080 先关闭
netstat –an
netstat –anb 来查看谁占用该8080
(2) 主动改变tomcat的端口.
到 conf/server.xml 文件中修改
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5fe015df.jpg)
#### 3、 能够正常启动,但是会导航到另外一个页面
去修改工具->管理加载项,把默认的导航给禁用即可
#### 4、浏览器显示404 Not Found
在访问 tomcat时候,一定要保证 tomcat 服务器是启动,不然就会出现这种错误。
### Tomcat的目录结构文件
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5fe17237.jpg)
**bin**: 启动和关闭tomcat的bat文件
**conf**: 配置文件
-->**server.xml **: 该文件用于配置和 server 相关的信息, 比如 tomcat启动端口后,配置Host, 配置Context 即web应用
-->**web.xml** : 该文件配置与 web应用(web应用就相当于是一个 web站点)
-->**tomcat-users.xml**: 该文件用户配置tomcat 的用户密码 和 权限
**lib** 目录: 该目录放置运行tomcat 运行需要的jar包
**logs** 目录:存放日志, 当我们需要去查看日志的时候,很有用!,当我们启动tomcat错误时候,可以查询信息.
**webapps** 目录: 该目录下,放置我们的web应用(web 站点), 比如:
建立 web1 目录 下面放置我们的html 文件 jsp 文件..图片... 则 web1就被当做一个web应用管理起来(☞ 特别说明tomcat 6.0 以后支持 tomcat 5 版本 还有别的设置)
**work**: 工作目录: 该目录用于存放jsp被访问后 生成的对应的 server文件 和.class文件
### 如何访问一个web应用的某个文件
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5fe6bebc.jpg)
PS:想要访问一个WEB应用中的某个文件可以采用url(Uniform Resource Locator)统一资源定位符来访问,其格式如上。
### Tomcat应用部署目录结构规范
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5fe88f5b.jpg)
### Tomcat管理虚拟目录
需求:当希望将web应用部署到非webapps目录下时,怎么解决这问题。
PS:可以通过虚拟目录配置技术解决。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5fea56bd.jpg)
#### 配置步骤
1、找到server.xml文件
2、编辑host节点,添加Context path
<Context path="/应用名" docBase="web应用所在的绝对路径"/>
例如:要访问该web应用根目录下的hello.html文件
实际访问时输入的地址:http://localhost:8088/应用名/hello.html
3、重启、重新部署生效
#### context的几个属性的说明
**path**: 应用名称
**docbase**: web应用所在的绝对路径
**reloadable**: 如果设为ture ,表示 tomcat 会自动更新 web应用,但是这个开销大,建议在开发过程中,可以设为true, 但是真的发布了,则应当设为false
**upackWAR**: 如果设为 ture ,则自动解压,否则不自动解压.
PS:war包的打包和Tomcat怎么部署war包可以使用搜索引擎找到。
### 配置域名
实现的步骤如下:
(1) 在C:\WINDOWS\system32\drivers\etc 下的host文件 添加127.0.0.1 www.myweb.com
(2) 在tomcat 的server.xml文件添加主机名
~~~
<Host name="www.myweb.com" appBase="d:\web3”>
<Context path="/" docBase="d:\web3" />
</Host>
~~~
(3) 在d:\web3 加入了一个 /WEB-INF/web.xml 把 hello2.html设为首页面,如果连端口都不希望带,则可以把tomcat的启动端口设为80即可.
(4) 重启生效
### Tomcat框架机制
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5febe08e.jpg)
### Tomcat配置默认主机
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5fee2b10.jpg)
在tomcat/conf/server.xml 文件
<Engine name="Catalina" defaultHost="主机名">
如:<Engine name="Catalina" defaultHost="www.myweb.com">
----------参考《韩顺平.细说Servlet》
CS结构与BS结构
最后更新于:2022-04-01 09:41:57
# CS结构与BS结构
### 基本概述
B/S结构即浏览器和服务器结构。它是随着Internet技术的兴起,对C/S结构的一种变化或者改进的结构。在这种结构下,用户工作界面是通过WWW浏览器来实现,极少部分事务逻辑在前端(Browser)实现,但是主要事务逻辑在服务器端(Server)实现,形成所谓三层3-tier结构。
C/S 结构,即大家熟知的客户机和服务器结构。它是软件系统体系结构,通过它可以充分利用两端硬件环境的优势,将任务合理分配到Client端和Server端来实现,降低了系统的通讯开销。
PS:像腾讯就是以C/S结构起家的,其旗下的QQ这一软件就是典型的C/S结构应用,像Facebook就是以B/S为结构的。B/S结构的好处就是方便,不跨平台性好,真正的实现了一次开发,处处运行。C/S结构以其稳定安全著称,降低了通讯代价,但是实现起来麻烦,需要开发服务器和客户端两套系统并且在不同的平台移植起来非常麻烦。所以现在大多是以C/S模式来开发。
### C/S系统结构
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5fcde17c.jpg)
### B/S系统结构
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-23_56cbf5fd09bf6.jpg)
实例:
~~~
/**
模拟的简单Web服务器
*/
import java.io.*;
import java.net.*;
public class Servlet1{
public static void main(String[] args) throws Exception{
// 创建ServerSocket
ServerSocket ss = new ServerSocket(9999);
Socket s = ss.accept();
System.out.println("9999");
OutputStream os = s.getOutputStream();
BufferedReader br = new BufferedReader(new FileReader("c:\\hello.html"));
String buf = "";
while((buf = br.readLine()) != null){
os.write(buf.getBytes());
}
br.close();
os.close();
s.close();
}
}
~~~
----------参考《韩顺平.细说Servlet》
前言
最后更新于:2022-04-01 09:41:55
> 原文出处:[Servlet学习笔记](http://blog.csdn.net/column/details/switch-servlet.html)
作者:[q547550831](http://blog.csdn.net/q547550831)
**本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!**
# Servlet学习笔记
> 从CS结构到BS结构,从HTTP协议到Cookie技术,从Servlet入门到深入,详尽的描述了Servlet技术,方便对后续的JSP技术有更深层次的理解。