Servlet
Servlet是一个java接口,为我们封装好了处理HTTP请求的各种方法,而从达到浏览器和服务器的交互的目的,主要是处理Http请求并返回响应
Servlet是单例的,多用户访问创建多线程执行,即参数是栈内存独享,而成员变量有线程安全问题,需要加synchonized锁
Tomcat
Tomcat是一个Servlet容器,能运行.class文件,也是Jsp容器能处理动态资源,还是Web服务器也就是说能处理Hmlt,Css等,Tomcat启动时读取webapps下各站点web.xml文件里的信息,加载对应类,然后反射的实例化他们
web.xml常用的xml元素
代码语言:javascript复制<web-app>
<display-name></display-name> 定义了WEB应用的名字
<description></description> 声明WEB应用的描述信息
<context-param></context-param> 声明站点范围内的初始化参数
<filter></filter> 声明一个过滤器
<filter-mapping></filter-mapping> 与声明的filter关联来映射url
<listener></listener> 声明一个listener
<servlet></servlet> 声明一个servlet
<servlet-mapping></servlet-mapping> 与声明的servlet关联来映射url
<welcome-file-list></welcome-file-list> 指示服务器在收到引用一个目录名而不是文件名的URL时,使用哪个文件
<error-page></error-page> 在返回特定HTTP状态代码时,或者特定类型的异常被抛出时,能够制定将要显示的页面
</web-app>
元素的配置
代码语言:javascript复制<listener>
<listerner-class>listener.SessionListener</listener-class>
</listener>
<context-param>
<param-name>ContextParameter</para-name>
<param-value>test</param-value>
<description>It is a test parameter.</description>
</context-param>
<servlet>
<servlet-name>ServletConfigTest</servlet-name>
<servlet-class>pratices.ServletConfigTest</servlet-class> // 完整限定类名
<init-param>
<param-name>name</param-name>
<param-value>Howl</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ServletConfigTest</servlet-name>
<url-pattern>/ServletConfigTest</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/404.html</location>
</error-page>
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
其中映射url通配符,容器会减去站点的上下文路径才去匹配
- 路径匹配:/ 开头,/* 结尾,即 /Howl/*
- 扩展名匹配: *. 开头,即 *.html
- 缺省匹配:/ ,即都没找到的就来这个,访问任何资源都是在访问Servlet,缺省就会找图片或网页,再找不到就404(小猫页面)
其中
- 在web站点启动时就加载创建实例及调用init()方法,可用于定时任务,eg:日志与备份
- 正数一般是1表示加载实例化,不写或负数则第一次请求才实例化
1. 使用流程
1.1 创建测试类实现Servlet接口,其中有五个方法
代码语言:javascript复制public class ServletTest implements Servlet {
public void destroy() {
}
public ServletConfig getServletConfig() {
return null;
}
public String getServletInfo() {
return null;
}
public void init(ServletConfig arg0) throws ServletException {
}
public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {
}
}
1.2 显然service() 是我们处理请求的地方,所以我们在Service()方法里面写入
代码语言:javascript复制arg1.getWriter().write("Hello World"); //字符流
1.3 写完Service()是不够的,我们还需要让Tomcat知道怎么调用,何时调用该Servlet,即要在web.xml钟配置他
配置web.xml
代码语言:javascript复制<servlet>
<!-- 配置一个名字 -->
<servlet-name>ServletTest</servlet-name>
<!-- 对应的Servlet类 -->
<servlet-class>com.howl.controller.ServletTest</servlet-class>
</servlet>
<servlet-mapping>
<!-- 需要映射的Servlet名字 -->
<servlet-name>ServletTest</servlet-name>
<!-- 映射地址 -->
<url-pattern>/HelloWorld</url-pattern>
</servlet-mapping>
1.4 输入对应的映射地址访问
2. Servlet生命周期
- 加载:Tomcat第一次访问该Servlet时加载对应的Class并且创建该实例,属于单例,并发访问则创建多线程
- 初始化:实例化后调用Servlet内部的init()函数初始化
- 处理服务:浏览器访问该类时调用service()方法
- 销毁:Tomcat关闭或者主动调用destory该类会被销毁
- 卸载:等待GC,如果有需要再次使用这个Servlet,会重新调用init()方法进行初始化操作。
3. HttpServlet
我们开发时直接继承HttpServlet类,该类实现了Servlet的所有方法,并且增加了HTTP协议的处理方法,比Servlet更有优势,我么只需要重写doGet()和doPost()就可以了
代码语言:javascript复制public class ServletTest extends HttpServlet {
//处理Get请求
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
//处理Post请求
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
4. ServletConfig
每个HttpServlet都有这个对象,用来获取在web.xml里面的单独配置的初始化参数,在web.xml中更加灵活,修改数据不用改动代码 <init-param>
public class servletAuth extends HttpServlet {
ServletConfig servletConfig = this.getServletConfig();
String value = servletConfig.getInitParameter("name");
}
5. ServletContext
代表着当前web站点,所有servlet共享该资源,可以直接获取,这里this指代HttpServlet
代码语言:javascript复制public class servletAuth extends HttpServlet {
ServletContext servletContext = this.getServletContext();
servletContext.getInitParameter("name");
}
可用于Servlet间通信、可获取站点信息/资源
代码语言:javascript复制servletContext.setAttribute("name", "object"); //设置域属性,可设置对象
servletContext.getResourceAsStream("address"); //因为代表本站点,所以从根目录开始即与WEB-INF同级
以前类文件和资源文件同级可以直接访问,因为是JVM运行,而现在是Tomcat运行要遵守其目录规则 src下的资源要去classes下访问 与WEB-INF同级可直接访问
6. HttpServletResponse响应
Response向浏览器输出内容,Tomcat每收到一个Http请求就会为其创建request和response对象
Servlet流用完之后,Servlet引擎会从response中取数据,将数据当成响应正文处理
返回数据,Tomcat使用ISO 8859-1,不支持中文
代码语言:javascript复制// 响应二进制
response.setHeader("Content-Type", "text/html;charset=UTF-8"); // 设置网页请求头接收编码,
response.getOutputStream().write("你好世界".getBytes("UTF-8")); // Stream类传输二进制,中文要先变成二进制,不写编码默认用系统的gbk2312,因为调用的是java函数
// 响应字符串
response.setCharacterEncoding("UTF-8"); // 设置响应对象编码
response.getWriter().write("你好世界") // 此时调用Tomcat的writer会使用自带的ISO编码,需要在前设置
// 简化设置,第一个代表了上面两个
response.setContentType("text/html;charset=UTF-8")
response.setHeader("Content-Type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
下载
代码语言:javascript复制File file = new File("/download/test.png");
FileInputStream fileInputStream = new FileInputStream(file);
ServletOutputStream servletOutputStream = response.getOutputStream();
//设置响应头为下载,后面url编码为了文件名中文能适应
response.setHeader("Content-Disposition", "attachment; filename=" URLEncoder.encode(file.getName(), "UTF-8"));
int length = 0;
byte[] bytes = new byte[1024];
while( (length = fileInputStream.read(bytes)) != -1 ){
servletOutputStream.write(bytes, 0, length);
}
servletOutputStream.close();
fileInputStream.close();
重定向
代码语言:javascript复制response.sendRedirect("/404.html");//本地发生的,地址栏发生了变化(302)
压缩响应数据,这是浏览器解码
代码语言:javascript复制response.setHeader("Content-Encoding","gzip")
自动刷新 跳转
代码语言:javascript复制response.setHeader("Refresh","3;url=index.html")
禁止缓存
代码语言:javascript复制response.setHeader("Cache-Control","no-cache")
设置Cookie,Cookie后面会介绍
代码语言:javascript复制void addCookie(Cookie cookie)
7. HttpServletRequest
常用方法
代码语言:javascript复制request.setCharacterEncoding("UTF-8"); // 设置request编码,针对POST表单,get在url上,不在request中不起作用
request.getRemoteAddr() // 获取发送请求的IP
request.getRemotePort() // 获取发送请求的端口
request.getRequestURL() // 获取请求的完整地址
request.getMethod() // 获取请求方法,应再补上.equalsIgnoreCase
request.getHeader("请求头参数") // 获取请求头
request.getPathInfo() // 获取 / 开头的额外信息,servlet之后,请求参数之前的数据
request.getParameter("userId"); // 获取参数
request.getParameterValues(String name) // 获取复选框那种多数据的
request.getAttribute() // 在request对象域上存放数据,可用于转发
request.getRequestDispatcher("/index.html").forward(request,response) // 实现转发,带上域数据,服务器发生的,本地地址栏没变化,而且 / 代表该站点根目录,即WEB-INF同级
获取Cookie
代码语言:javascript复制Request.getCookies(); //获得一个数组,里面包含所有对象
Request.getSession(); //获取当前浏览器的Session
get请求中文乱码,Tomcat使用了ISO
代码语言:javascript复制byte[] bytes = request.getParameter("name").getBytes("ISO8858-1");
String reallyValue = new String(bytes,"UTF-8");
8. Cookie
Http是无状态的,但Cookie会话技术就可以解决这个问题,当浏览器访问服务器时,服务器给浏览器颁发一个Cookie里面记录了SessionId,当浏览器再次访问该服务器时就会带上对应的Cookie,这样服务器就会认识你拉。一个网站可以有多个cookie,每个cookie就是键值对加上必要的信息 eg:过期时间等
构造函数
代码语言:javascript复制Cookie(java.lang.String name, java.lang.String value)
常见方法
代码语言:javascript复制String getName()
String getValue()
void setValue(java.lang.String newValue)
int getMaxAge()
void setSecure(true) // https才带上
void setMaxAge(int expiry) // 负数本次会有有效,0代表删除,因无对应方法,本地也删除,默认-1
String getPath()
void setPath() // 设置资源可以访问的地址,默认是整个页面可以使用,设置之后只有指定path才能使用
String getDomain()
void setDomain(java.lang.String pattern) // 设置域
常见操作
代码语言:javascript复制// 设置response的编码
response.setContentType("text/html;charset=UTF-8");
// 实例化一个Cookie,注意导包是导入javax.servlet.http.Cookie,这个包在tomcat下
// URLEncoder在java.net包下,单参构造函数已废弃,中文属于Unicode编码四字节,英文ASCII两字节,需要转码,与早期打印机相关
Cookie cookie = new Cookie("name", URLEncoder.encode("我爱中国", "UTF-8"));
// 设置过期时间,单位为秒,-1有效到浏览器关闭
cookie.setMaxAge(1000);
// 设置额外二级域
cookie.setDomain("a.com");
// 响应头添加set-cookie
response.addCookie(cookie);
// 设置路径,一般cookie整个站点都可以用,但也可以只限制该地址可用
//cookie.setPath("/ServletConfigTest");
/*************************************/
// 返回包含所有对象的数组
Cookie[] cookies = request.getCookies();
for(Cookie cookieLoop : cookies){
String name = cookieLoop.getName();
String value = URLDecoder.decode(cookieLoop.getValue(), "UTF-8");
System.out.println(name "----" value);
}
9. HttpSession
Session是记录浏览器状态的机制,解决http无状态的另一种方式,Session能存放对象,并且Session是存在服务器端的,cookie只存字符串,所以Servlet能共享属于某个浏览器的Session
当浏览器访问服务器的Servlet,并且使用了response.getSession()才会自动给该浏览器颁发一个带JESSIONID的Cookie,JESSIONID就是唯一标识浏览器Session的id,该cookie默认生命周期为当前浏览器,所以关闭了浏览器Session就会失效
Session的有效期是访问一次就重置,而cookie的是累计,Session存放于服务器内存,超时会自动删除,默认超时为30min,一般存用户级别数据,即当前会话有效的
Session的活化和钝化(下篇Listener有提及)
钝化:服务器关闭时还有正常的Session存在并未超时,就会以文件的形式存储起来
活化:服务器再次开启时,恢复存储起来的Session对象
实现该功能的对象需要实现Serializable接口,涉及了序列化
方法
代码语言:javascript复制long getCreationTime() //获取Session被创建时间
String getId() //获取Session的id
long getLastAccessedTime() //返回Session最后活跃的时间
ServletContext getServletContext() //获取ServletContext站点对象
void setMaxInactiveInterval(int var1) //设置Session超时时间
int getMaxInactiveInterval() //获取Session超时时间
Object getAttribute(String var1) //获取Session属性,代替了getValue
Enumeration getAttributeNames() //获取Session所有的属性名
void setAttribute(String var1, Object var2) //设置Session属性,可存对象,在于域中
void removeAttribute(String var1) //移除Session属性
void invalidate() //销毁该Session
boolean isNew() //该Session是否为新的
常见操作
代码语言:javascript复制HttpSession httpSession = request.getSession();
httpSession.setAttribute("Session", "Howl");
System.out.println(request.getSession().getAttribute("Session"));
//当浏览器禁止了Cookie的时候,encodeURL的另一个功能,带上JESSIONID访问即URL地址重写,会自动判断浏览器是是否支持的
//通过在其中包含会话ID对指定的URL进行编码,或者,如果不需要编码,则返回不变的URL
//之后服务器端会自动获取该ID
response.sendRedirect(response.encodeURL(url));
验证码
代码语言:javascript复制//getCode()获取验证码存入Session
request.getSession.setAttribute("code", getCode());
//然后和requset获取的对比
request.getParameter("code") == request.getSession.getAttribute("code")
10. Servlet访问流程,网络图来自java3y
API参考 oracle官网文档
Web.xml参考 思否