您的位置:首页 > Web前端 > JavaScript

Servlet-JSP相关

2016-10-22 17:49 309 查看
EL表达式
EL 全名为Expression Language , EL表达式语言
目的:
使用EL 和 JSTL 取代jsp中的脚本 --> jsp页面中没有java代码(底层还需要执行相应的java代码)
作用:
获得域中的数据
执行运算
获得web开发常用对象
调用java对象方法
格式:${el表达式}
注意:如果数据不存在,将返回空字符串""
EL内置对象(11个)
作用域:pageScope 、requestScope、sessionScope、applicationScope
示例:${requestScope.属性名}
注意:如果没有显示说明从哪个作用域取,则底层调用pageContext.findAttribute(name)方法.从小到大取
JSP上下文对象:pageContext
示例:<%((HttpServletRequest)pageContext.getRequest()).getContextPath()%>
el:${pageContext.request.contextPath}
请求参数:
param.name      --> request.getParameter(name)
paramValues.name    -->request.getParameterValues(name)
请求头信息:
header.name     --> request.getHeader(name)
headerValues.name   --> request.getHeaders(name)
获得cookie : cookie
获得指定cookie名称的值:${cookie.cookie名称.value}
web项目的初始化参数:
initParam.name --> servletContext.getInitParameter(name)
4000
访问集合
访问List中的元素: list[0]
访问Map中的元素: map.key 或 map['key']
运算符
算术运算符 + - / % (5/2=2.5)
关系运算符 == != < <= > >=  (可以用对应英文缩写表示 eq ne lt le gt ge)
逻辑运算符 && || !  (非也可以用not)
其他
empty 表示是否为空 (null , "" , size()==0)  ${empty 变量名}
${表达式 ? true : false}    三目运算符
注意
访问属性eWaiJiFen时,要写 对象.EWaiJiFen

自定义标签库(了解)
概述
在jsp中书写自定义标签,在生成java代码时要被指定java代码替换,底层还是java代码
要关联自定义标签和替换的java代码,需要有配置文件(tld文件)
步骤
编写实现类
传统标签:必须实现Tag接口  --> 继承实现类 TagSupport ,如果需要标签体 继承BodyTagSupport (了解)
简单标签:必须实现SimpleTag接口 --> 继承实现类 SimpleTagSupport(源码tomcat中有)
编写配置文件 tld
使用
引入标签库 taglib
使用:<前缀:标签名称>
tld文件
标签库描述符(taglib description)
tld文件基于xml文件 ,扩展名为tld,但内容是xml
存放位置
1 WEB-INF目录下,但classes和lib目录除外
2 WEB-INF/lib目录下的jar文件中的META-INF目录下
tomcat将自动加载tld文件
示例(自定义foreach标签,用来遍历集合)
编写实现类
package tagImpl;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class MyTagImpl extends SimpleTagSupport{
//页面的属性必须对应一个set方法
ArrayList<String> list;
String item;
public void setList(ArrayList<String> list){
this.list=list;
}
public void setItem(String item){
this.item=item;
}
public void doTag() throws JspException,IOException{
PageContext page=(PageContext)this.getJspContext();
for(String str : list){
page.setAttribute(item, str);//存入page作用域,方便页面取出
this.getJspBody().invoke(page.getOut());//把标签体中的内容输出到浏览器
}
}
}
编写tld文件(位置:WEB-INF目录,名称任意)
<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd" version="2.1">
<!-- 版本 -->
<tlib-version>1.0</tlib-version>
<!-- 建议前缀 -->
<short-name>s</short-name>
<!-- 引用此文件的标识 -->
<uri>http://localhost:8080/demo/tagImpl/MyTagImpl</uri>

<!-- 定义标签 -->
<tag>
<!-- 标签名称 -->
<name>foreach</name>
<!-- 标签的实现类 -->
<tag-class>tagImpl.MyTagImpl</tag-class>
<!-- 标签体
取值:
JSP:不会用
empty:空,没有标签体
scriptless:支持EL表达式,不支持jsp脚本
tagdependent:不会用
-->
<body-content>scriptless</body-content>
<!-- 标签的属性 -->
<attribute>
<!-- 属性名称 -->
<name>list</name>
<!-- 是否是必须的 -->
<required>true</required>
<!-- 是否支持运行时表达式(EL) -->
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<!-- 属性名称 -->
<name>item</name>
<!-- 是否是必须的 -->
<required>true</required>
<!-- 是否支持运行时表达式(EL) -->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
使用
在页面引用标签库
<%@ taglib uri="http://localhost:8080/demo/tagImpl/MyTagImpl" prefix="s"%>
在页面使用标签
<s:foreach list="${list}" item="i">
${i}<br>
</s:foreach>
自定义标签细节(其实是自定义标签的生命周期)
1 父类SimpleTagSupport会缓存PageContext对象。可以PageContext page=(PageContext)this.getJspContext();获取jsp上下文对象
2 通过标签的属性attribute进行数据的传递,实现类需要提供相应的属性property的setter方法接受传递的数据
3 缓存了标签体,类型是JspFragment(代码片段),可以通过this.getJspBody()获得标签体.
可以执行invoke将标签体的内容输出到指定流中this.getJspBody().invoke(page.getOut());如果invoke参数为null,则默认输出到浏览器
4 doTag()方法,定义自定义标签功能的方法
如果在doTag标签体中,throw new SkipPageException(),表示当前标签执行之后,页面之后的内容将不输出。

自定义函数库(了解)
概述
在jsp中使用 ${fn:函数名(参数...)} 执行固定的java方法完成操作
要关联固定的java代码,需要有配置文件(tld文件)
示例
编写自定义类,类中编写要调用的方法,必须是静态的,例:
package function;
public class MyFunction {
public static String join(String i,String j){
return i + "/" + j;
}
}
编写tld文件(位置:WEB-INF目录,名称任意)
<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0">

<tlib-version>1.0</tlib-version>
<short-name>myfn</short-name>
<uri>http://localhost:8080/myFunctionTag/myFunction</uri>
<function>
<!-- 使用时的名称 -->
<name>join</name>
<!-- 对应的类 -->
<function-class>function.MyFunction</function-class>
<!-- 函数签名 -->
<function-signature>java.lang.String join(java.lang.String ,java.lang.String)</function-signature>
</function>
</taglib>
使用
引入标签库
<%@ taglib uri="http://localhost:8080/myFunctionTag/myFunction" prefix="myfn" %>
调用
${myfn:join("q","w")}

JSTL
JavaServer Pages Standard Tag Library, JSP标准标签库。
第三方实现apache
导入jar包(/jstl/)
jstl.jar            --> myeclipse自动添加的jar名称javax.servlet.jsp.jstl.jar
standard.jar        --> myeclipse自动添加的jar名称jstl-impl.jar
注意:myeclipse已经提供了相应的jar,并在将web项目发布到tomcat时,自动的将两个jar添加到web/WEB-INF/lib目录中
JSTL提供5种 标签库
核心库 : http://java.sun.com/jsp/jstl/core ,默认前缀:c
函数库 : http://java.sun.com/jsp/jstl/functions ,默认前缀:fn
国际化标签库,数据库标签库,XML标签库
核心库
先引入标签库
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
域操作
<c:set> 给指定作用域设置属性
var         属性的名称
value       属性的值
scope       作用域(page/request/session/application)
例:<c:set var="名称" value="值" scope="page"></c:set>
<c:remove/> 移除属性
var         要移除的属性的名称
scope       作用域,默认移除所有域中的指定名称的数据(page/request/session/application)
例:<c:remove var="username" />
<c:out> 向页面输出内容(可以进行html或js转义)
value       要输出的内容,支持EL表达式
escapeXml   是否进行标签内容转义(如:html代码在页面中原样输出,还是解析为html代码)默认为true
例:<c:out value="${username}"></c:out>
逻辑操作
<c:if> 相当于java中的if
test        判断条件
例:<c:if test="${empty username}">如果是真则输出</c:if>
注意:没有<c:else>
<c:choose> 相当于java中的switch
test        条件
子标签<c:when> 相当于java中的case
子标签<c:otherwise> 相当于java中的default
例:
<c:choose>
<c:when test="${param.num<10}">
num小于10
</c:when>
<c:when test="${param.num<20}">
num大于等于10且小于20
</c:when>
<c:otherwise>
num大于等于20
</c:otherwise>
</c:choose>
循环操作
<c:forEach> 循环
items       需要遍历的数据,支持EL表达式
var         循环时每一项数据存放的变量名称,可以从域中获取当前项.只能在标签体内使用
begin       循环初始值
end         循环结束值
例:
遍历集合或数组
<c:forEach items="${list}" var="obj">
${obj} <br/>
</c:forEach>
遍历Map
<c:forEach items="${map}" var="entry">
${entry.key} --> ${entry.value} <br/>
</c:forEach>
指定范围的循环
<c:forEach begin="1" end="9" var="i">
${i} <br/>
</c:forEach>
注:访问对象的属性,就是调用对象的get方法
其它常用操作
<c:url> 将url添加项目名称后添加到域中
var         添加域中的属性的名称
value       要添加到域中的url
子标签<c:param> 给url后添加参数,此标签在<c:url>标签体中使用
name        参数名称
value       参数值,可以自动进行中文编码(base64)
例:
<c:url var="oneURL" value="/oneServlet">
<c:param name="username" value="sss"></c:param>
</c:url>
<c:redirect> 重定向
url     要重定向的url,特别注意:当以/开头时不需要加项目名称
例:<c:redirect url="/index.jsp"></c:redirect>
函数库
先引入标签库
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
用法:
${fn:函数名(参数...)}
包含了一下处理字符串的常用方法

JSP模式
模式1 : JSP + JavaBean
小型项目,开发速度快。不好处扩展差,不易维护
模式2 : JSP + Servlet + JavaBean (推荐)
模式2 基于MVC思想

MVC设计模式
MVC 软件设计模式,思想:一种分离业务逻辑与显示界面的设计方法 (业务逻辑 与 显示页面 相分离)
模块
Model模型 , 负责管理程序的业务数据
View视图 ,负责显示界面
Controller控制器 ,负责与用户进行交互(接收请求和选择响应视图)

经典三层体系架构
在程序业务更加复杂的时候,会将Controller控制层继续划分为三层.
表示层(web层)
业务逻辑层(service层)
数据访问层(dao层)

监听器Listener
servlet 三种技术 : servlet,listener(监听器),filter(过滤器)
web提供8接口,分别对ServletContext、HttpSession、ServletRequest 对象自身、属性(域)进行监听
域对象自身(3个)
ServletContextListener ,对ServletContext对象进行监听 (对象创建,与对象销毁)
HttpSessionListener ,对HttpSession对象进行监听 (对象创建,与对象销毁)
ServletRequestListener ,对ServletRequest对象进行监听 (对象创建,与对象销毁)
以上三个监听器,都提供了事件对象 xxxEvent,获得被监听对象。
需要在web.xml文件中进行注册。tomcat自动触发响应的方法。
域内容(对象属性)(3个)
ServletContextAttributeListener  对ServletContext属性进行监听 (属性添加,移除,替换)
HttpSessionAttributeListener 对HttpSession属性进行监听  (属性添加,移除,替换)
ServletRequestAttributeListener 对ServletRequest属性进行监听 (属性添加,移除,替换)
需要在web.xml文件中进行注册。tomcat自动触发响应的方法。
session中javabean(2个)
HttpSessionBindingListener : 对实现此接口的javabean在session域中的状态进行监听(绑定状态)
valueBound(HttpSessionBindingEvent event) ,当javabean对象添加到session属性触发此方法 (绑定)
void valueUnbound(HttpSessionBindingEvent event) ,当javabean对象从session属性移除时,触发此方法 (取消绑定)
应该以被监听的javaBean继承此接口,并且不需要再web.xml中注册
HttpSessionActivationListener : 对实现此接口的javabean在session域中的状态进行监听(持久化状态)
void sessionDidActivate(HttpSessionEvent se) ,在服务器启动时,如果已经钝化了javabean,则将javabean重新加载进内存。(活化 :硬盘 --> 内存 )
void sessionWillPassivate(HttpSessionEvent se) ,如果javabean在session中,当服务器正常关闭时,进行持久化此对象。(钝化 : 内存 --> 硬盘)
钝化时数据保持位置:%tomcat%\work\Catalina\localhost\day14_listener\SESSIONS.ser
应该以被监听的javaBean继承此接口,并且不需要在web.xml中注册
javabean必须实现java.io.Serial
13c7b
izable接口
注册监听器(web.xml)
<listener>
<listener-class>类的完全限定名</listener-class>
</listener>
HttpSessionAttributeListener 和 HttpSessionBindingListener 区别:
HttpSessionAttributeListener ,对所有javabean生效
HttpSessionBindingListener ,对实现了此接口javabean生效
对同一件事的监听角度不同,一个从session角度进行监听,一个从javaBean角度进行监听

国际化(i18n)
程序的界面可以支持多国语言。 internationalization ,i18n
国际化资源文件
文件名称:baseName_语言_国家|地区.properties
baseName,基名,自定义
后面的语言和国家不能乱写,可参见IE浏览器的internet选项-->常规-->语言 中的选项
例如:
message_zh_CN.properties ,简体中文
message_zh_TW.properties ,繁体中文
message_en.properties ,英语
message.properties ,默认配置文件
默认位置:src,ResourcBundle.getBundle("baseName");
Locale 对象表示了特定的地理、政治和文化地区
Locale(String language, String country) 指定 语言,国家|地区
例如 new Locale("zh", "CN")
使用时
文本
ResourceBundle.getBundle("message" ,request.getLocale()); 对资源文件进行解析,可以指定 Locale对象设置不同的语言
getString("usernameMsg") 获得指定名称的对象
数字
数字 NumberFormat.getNumberInstance(request.getLocale()).format(double)
百分比 NumberFormat.getPercentInstance(request.getLocale()).format(double)
货币 NumberFormat.getCurrencyInstance(request.getLocale()).format(double)
日期时间
DateFormat.getDateTimeInstance ,处理日期时间
DateFormat.getDateInstance  处理日期
DateFormat.getTimeInstance  处理时间
样式:FULL 、LONG 、MEDIUM (默认) 、 SHORT
消息格式化
MessageFormat.format ,将字符串中{n}进行内容自动的填充。
示例
在src下添加message_zh_CN.properties
usernameMsg=用户名
passwordMsg=密码
在src下添加message_en.properties
usernameMsg=username
passwordMsg=password
jsp页面
<%
ResourceBundle bundle = ResourcBundle.getBundle("message",request.getLocale());
%>
<%=bundle.getString("usernameMsg") %> : <input name="username"/> <br/>
<%=bundle.getString("passwordMsg") %> : <input type="password" name="password"/>
在IE浏览器的internet选项-->常规-->语言 中选择不同的语言,则网页显示效果不同

过滤器Filter
对tomcat的请求会优先由过滤器进行处理
编写流程
1 编写实现类 ,实现Filter接口 (javax.servlet.Fitler)
2 在web.xml配置
格式
<filter>
<filter-name>随便起个名,注意不要重复,一般为类名</filter-name>
<filter-class>实现类的全限定名称</filter-class>
</filter>
<filter-mapping>
<filter-name>上面的filter-name</filter-name>
<url-pattern>/*</url-pattern>
<!-- <dispatcher>request</dispatcher> -->
</filter-mapping>
注意
<url-pattern>和servlet的<url-pattern>用法相同,可参加<Servlet访问路径配置>
url-pattern和dispatcher标签可以有多个

Filter接口(javax.servlet)
所有过滤器需要实现的父接口
方法
void init(FilterConfig filterConfig) 初始化
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 过滤到请求时执行的方法
void destroy() 销毁
注意 chain.doFilter(request,response);为放行

过滤器的生命周期
init ,初始化
时间:tomcat启动时。只要注册了过滤器,则tomcat就进行实例化
参数:
FilterConfig,当前过滤器配置对象
getFilterName() ,获得过滤器配置的名称<filter-name>的值
getInitParameter(java.lang.String name) 获得指定名称,过滤器初始化参数的值
getInitParameterNames() 获得所有的初始化参数的名称
getServletContext() 获得servlet的上下文对象
doFilter ,过滤执行
时间:接收到请求时。
参数:
FilterChain对象 过滤器链对象
服务器tomcat将所有符合要求的过滤器生成了一个链。
过滤器使用 FilterChain 调用链中的下一个过滤器,如果调用的过滤器是链中的最后一个过滤器,则调用链末尾的资源。
方法
void doFilter(ServletRequest request, ServletResponse response) 放行
注意:
过滤器链中的所有过滤器的顺序,取决于web.xml配置文件<filter-mapping>配置顺序
tomcat6.0 web.xml文件中<filter> 必须在<filter-mapping>之前
destroy,销毁
时间:服务器正常关闭时

配置Filter的初始化参数
在web.xml中<filter>中的<filter-class>后添加<init-param>
例:
<filter>
<filter-name>
<filter-class>
<init-param>
<param-name>参数名</param-name>
<param-value>参数值</param-value>
</init-param>
</filter>

dispatcher标签(过滤器的过滤类型)
位置:<filter-mapping>中的末尾
作用:设置当前过滤器的过滤类型
取值:
REQUEST,request : 对请求进行过滤(默认)
FORWARD,forward : 在进行请求转发时进行过滤
INCLUDE,include : 在进行包含操作时进行过滤
ERROR,error : 当页面出现错误,执行友好页面(web.xml <error-page>)时进行过滤
ASYNC,async :异步,Servlet3.0提供,用servlet3.0新技术异步时进行过滤。
注意
取值为FORWARD,INCLUDE,ERROR时,url-pattern应该写要转发到的页面或要包含的页面的url
当取值为ERROR时,可以不能看到自定义的错误页面,而是浏览器的错误页面.可在过滤器放行前将状态码设置为200(先强转).例:response.setStatus(200);

过滤器案例
处理中文乱码(post)
添加过滤器,<url-pattern>为/*
在过滤器的doFilter方法放行前设置
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=UTF-8");
设置图片缓存时间
http响应提供三个头,进行页面缓存设置
pragma : no-cache
cache-control : no-cache
expires : 0
添加过滤器,<url-pattern>为*.jpg
在过滤器的doFilter方法放行前设置
response.setDateHeader("expires",System.currentTimeMillis() + 60 * 60 * 1000 * 24 * 30L); //一个月,加L是为了防止溢出

处理中文乱码工具类
思想:
对request的getParameter和getParameterMap方法进行增强,在其中处理get中文乱码.然后将增强后的自定义request对象传递给servlet
tomcat提供了HttpServletRequestWrapper作为HttpServletRequest接口的装饰类,无任何增强的方法,供编程人员使用
代码:
package filter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
public class EncodingFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {

}
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
//强转
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
//处理post请求乱码
request.setCharacterEncoding("utf-8");
//实例化自己的类(装饰者模式,增强了request的getParameter和getParameterMap方法,处理get请求乱码)
MyRequest myRequest = new MyRequest(request);
//放行
chain.doFilter(myRequest, response);//传递自己的类对象
}
public void destroy() {

}
}
/**
* 自定义的用于增强tomcat的request对象的类
* @author Administrator
* HttpServletRequestWrapper为HttpServletRequest接口的装饰类,不过无任何增强的方法,供编程人员使用
*/
class MyRequest extends HttpServletRequestWrapper{
public MyRequest(HttpServletRequest request) {
super(request);//父类缓存起来了
}
//增强方法
public String getParameter(String name){
//获取原来的值
String value = super.getParameter(name);
if(value == null){
return null;
}
//对get请求乱码问题处理
if(super.getMethod().equalsIgnoreCase("get")){
//get请求
try {
value = new String(value.getBytes("ISO8859-1"),super.getRequest().getCharacterEncoding());
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
return value;
}
public Map<String, String[]> getParameterMap(){
Map<String,String[]> map = super.getParameterMap();
try {
if(super.getMethod().equalsIgnoreCase("get")){
Map<String,String[]> map2 = new HashMap<String,String[]>();
for(String key : map.keySet()){
String[] value = map.get(key);
for(int i=0;i<value.length;i++){
value[i] = new String(value[i].getBytes("ISO8859-1"),super.getCharacterEncoding());
}
map2.put(key, value);
}
map = map2;
}
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
}
web.xml配置
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

页面静态化
原因
每次请求会查询数据库,动态生成静态网页,速度很慢.对于一些固定的或访问量很大,很少更新的页面,可以使用静态页面
思想
首次访问Servlet将数据保存为静态html页面(而不是发送到浏览器),然后将html页面发送到浏览器.以后的访问不用查询数据库,直接返回第一次访问生成的html页面
Servlet(JSP)的响应内容默认通过request.getWriter方法输出到浏览器,增强response的getWriter方法修改目标输出位置
tomcat提供了HttpServletResponseWrapper作为Response接口的装饰类,无任何增强的方法,供编程人员使用
代码
package web.filter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
public class PageStaticFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {

}
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
//强转
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
//获取文件名(这里根据自己的需求写)
String id = request.getParameter("id");
String fileName = "/html/" + id + ".html";
//获取全路径
String filePath = request.getSession().getServletContext().getRealPath(fileName);
//判断文件是否存在
File htmlFile = new File(filePath);
if(!htmlFile.exists()){
//不存在
MyResponse myResponse = new MyResponse(response,htmlFile);
//放行
chain.doFilter(request, myResponse);//通过增强方法,会将数据保存为静态页面
}
//将文件发送给浏览器
request.getRequestDispatcher(fileName).forward(request, response);
}
public void destroy() {

}
}
/**
* 自定义的response类,修改getWriter方法的功能
* @author Administrator
* HttpServletResponseWrapper为tomcat的Response对象的装饰类,没有修改任何方法,供开发人员使用
*/
class MyResponse extends HttpServletResponseWrapper{
private File htmlFile;//缓存的文件
PrintWriter writer;//缓存的打印流
public MyResponse(HttpServletResponse response,File htmlFile) {
super(response);
this.htmlFile = htmlFile;
}
//增强方法(将目的地改为指定文件)
public PrintWriter getWriter() throws IOException {
//此方法会调用两次,第一次tomcat获得流用来输出,第二次tomcat获得流是为了关闭流
if(writer == null){
//第一次调用,实例化打印流
String encoding = super.getResponse().getCharacterEncoding();//编码
OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(htmlFile),encoding);//转换流
writer = new PrintWriter(out);//此类编码为操作系统默认编码,要使用转换流指定编码,否则将出现乱码
}
return writer;
}
}
web.xml配置
<filter>
<filter-name>PageStaticFilter</filter-name>
<filter-class>web.filter.PageStaticFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>PageStaticFilter</filter-name>
<url-pattern>路径自己写,某个servlet</url-pattern>
</filter-mapping>

javamail
应用场景
注册账号时,进行账号激活
邮件订阅
生日祝福
名词
邮件服务器:安装有接收邮件、发送邮件功能的软件的计算机。
电子邮箱email:邮件服务器上申请的账号。
协议
SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,发送邮件服务器称为SMTP服务器,默认端口号:25
POP3(Post Office Protocol 3)即邮局协议,接收邮件服务器称为POP3服务器。默认端口:110
IMAP(Internet Mail Access Protocol)交互邮件访问协议,接收邮件服务器。默认端口:143
与POP3协议的主要区别是用户可以不用把所有的邮件全部下载,可以通过客户端直接对服务器上的邮件进行操作
发送邮件过程
xxx@163.com 发送到 xxx@126.com
首先发送到163邮件服务器的SMTP发送端,然后发送到126邮件服务器的SMTP发送端,并保存.
当用户读取时,通过126邮件服务器的POP3接收端读取邮件,返回给用户
手动发送邮件示例
命令行
telnet smtp.163.com 25      --连接163邮件服务器的smtp发送端(一般都为smtp.服务器.com)
ehlo itcast                 --随便说点啥
auth login                  --需要登陆
aXRjYXN0X2x0                --用户名(base64编码)
MXFhejJ3c3g=                --密码(base64编码)
mail from:<itcast_lt@163.com>   --发件人
rcpt to:<itcast_lt@126.com>     --收件人
data                            --需要书写邮件内容
from:<lkplovelyf@163.com>   --显示的发件人
to:<itcast_lt@126.com>      --显示的收件人
subject:good luck!!!        --主题
[空行]                      --与正文的分割
baidu welcome you!!!        --正文
.                           --结束邮件主体
quit                        --断开连接
base64编码与解码
解码:
sun.misc.BASE64Decoder类
sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
byte[] bytes = decoder.decodeBuffer("要解码的字符串");
System.out.println(bytes);
编码:
sun.misc.BASE64Encoder类
sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
String str = encoder.encode("要编码的字符串".getBytes());
System.out.println(str);
注意:
myeclipse默认没有上面两个类,换个jre库就好了(没搞明白为什么)
项目右键-->Properties-->Java Build Path-->Libraries-->删除原来的-->Add Library-->JRE System Library
javamail
使用java程序发送电子邮件。
sun公司提供
核心jar:mail.jar           --> javamail1_4_5.zip
依赖jar:activation.jar     --> jaf-1_1_1.zip (编写复杂邮件时使用,现阶段不用)
javamail 编写流程
1 获得会话 Session  -->相当于连接
2 编写消息 Message  -->相当于邮件
3 发送邮件 Transport
工具类
import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.Message.RecipientType;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
/**
* 邮件工具包
* @author Administrator
*
*/
public class MailUtils {
private static String serverHost = "localhost";//邮箱服务器地址(例:smtp.163.com)
private static String mail_username = "123";//用户
private static String mail_password = "123";//密码
private static String sendHost = "123@ss.cn";//发送人地址
/**
* 向用户发送邮件
* @param sendToUrl 目标邮箱
* @param subject 主题
* @param content 正文
*/
public static void sendMail(String sendToHost,String subject,String content){
try {
//获得会话
// * 准备参数
// ** 1 准备配置信息
Properties props = new Properties();
props.setProperty("mail.host", serverHost);//邮箱服务器地址
props.setProperty("mail.smtp.auth", "true");//进行登录验证
// ** 2 准备用户和密码
Authenticator authenticator = new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(mail_username, mail_password);
}
};
Session session = Session.getDefaultInstance(props, authenticator);
//session.setDebug(true);// 设置debug模式 在控制台看到交互信息
//编写消息
Message message = new MimeMessage(session);
// * 1 设置发件人
message.setFrom(new InternetAddress(sendHost));
// * 2 设置收件人
message.setRecipient(RecipientType.TO, new InternetAddress(sendToHost));
//TO:接收者;CC:抄送;BCC:暗送;(接收者知道所有被抄送的人,但不知道被暗送的人)
// * 3 设置主题
message.setSubject(subject);
// * 4 设置正文
message.setContent(content, "text/html;charset=utf-8");
//发送
Transport.send(message);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
sendMail("456@ss.cn","主题1","正文");
}
}

MIME类型
概述
多用途互联网邮件扩展(MIME,Multipurpose Internet Mail Extensions)
规定了各种各样数据类型的符号化方法,使邮件能够支持非ASCII字符,二进制格式附件等多种格式的消息
HTTP协议中也使用了MIME的框架,标准被扩展为互联网媒体类型
格式:content-type : type/subtype;parameter
例如:text/html;charset=UTF-8
type的所有取值
Text:用于标准化地表示的文本信息,文本消息可以是多种字符集和或者多种格式的;
Multipart:用于连接消息体的多个部分构成一个消息,这些部分可以是不同类型的数据;
Application:用于传输应用程序数据或者二进制数据;
Message:用于包装一个E-mail消息;
Image:用于传输静态图片数据;
Audio:用于传输音频或者音声数据;
Video:用于传输动态影像数据,可以是与音频编辑在一起的视频数据格式。
subtype常见取值
text/plain(纯文本)
text/html(HTML文档)
image/gif(gif图像)
image/jpeg(jpeg图像)
image/png(png图像)
application/msword(Microsoft Word文件)
application/x-www-from-urlencoded(HTTP的POST方式提交表单)
multipart/form-data (用于文件上传)
%tomcat%/conf/web.xml 提供常见的MIME类与扩展名的映射关系。

案例:使用本地服务器发送邮件
软件介绍
易邮邮件服务器:邮件服务器软件,可以注册账号发送和接收邮件
Foxmail:使用客户端管理邮箱
安装易邮邮件服务器
设置易邮邮件服务器
工具-->服务器设置-->作为局域网的邮件服务器,单域名:ss.cn
新建账号
账号123     账号123     联系邮件地址123@ss.cn
账号456     账号456     联系邮件地址456@ss.cn
安装Foxmail
设置Foxmail
第一次启动时创建用户:手动设置
邮件账号    123@ss.cn
密码        123
POP服务器   localhost
SMTP服务器  localhost
启动后创建用户:在已有用户上右击-->设置-->新建-->手动设置
邮件账号    456@ss.cn
密码        456
POP服务器   localhost
SMTP服务器  localhost
可以试试用Foxmail用两个账号互相发送邮件
使用java代码发送邮件
设置工具类MailUtils中的成员变量的值
private static String serverHost = "localhost";//邮箱服务器地址(例:smtp.163.com)
private static String mail_username = "123";//用户
private static String mail_password = "123";//密码
private static String sendHost = "123@ss.cn";//发送人地址
发送邮件
MailUtils.sendMail("456@ss.cn","主题","正文");

文件上传
概述
将用户本地的资源,通过浏览器发送给服务器,服务器保存到服务器端
浏览器:选择文件,提交
服务器:获得数据,保存
步骤
1 通知浏览器,可以选择文件、可以将文件进行提交
提交: <form> <input type="submit"/>
选择:<input type="file" name=""/>
发送上传内容:给form表单添加属性enctype="multipart/form-data" ,设置method="post". 注意:默认情况只发送文件的名称
enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码
取值:
application/x-www-form-urlencoded 在发送前编码所有字符(默认)
multipart/form-data 不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。
注意:
上传文件时,request.getParameter方法不能获取方法体传递的参数
可以在表单的action后面使用?追加参数
可以在当前servlet上添加servlet3.0的注解@MultipartConfig
2 服务器接收数据,并保存文件。
第一种:使用servlet的api解析上传内容,需要手动对内容进行分析。比较繁琐
request提供的getInputStream() 用来获得请求体的所有内容。
第二种:使用第三方工具 -- apache commons组件--fileupload
jar
核心jar:commons-fileupload-1.2.2.jar   --> 来自commons-fileupload-1.2.2-bin.zip
依赖jar:commons-io-2.3.jar             --> 来自commons-io-2.3-bin.zip
核心类:ServletFileUpload
api见工具类
第三种:Servlet3.0支持文件上传,参见下面的<servlet3.0>
第四种: struts2的文件上传,参见<struts>中的<文件上传>
工具类FileUploadApacheUtils
package util;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
public class FileUploadApacheUtils {
/**
* 处理文件上传
* @param request 请求对象
* @return Map:普通表单字段的name-value,上传文件的name-保存名称
*/
@SuppressWarnings("unchecked")
public static Map<String,String> fileUpload(HttpServletRequest request){
//判断是否表单是否是文件上传 ,即判断enctype是否为"multipart/form-data"
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if(!isMultipart){
throw new RuntimeException("表单不是文件上传类型");
}
int sizeThreshold = 1024 * 1024;//设置临界点大小,当文件大小大于临界点大小时,将会产生临时文件
String tempPath = "/WEB-INF/tempFile";//临时文件存放位置
String savePath = "/WEB-INF/uploadFile";//保存路径
Map<String,String> map = new HashMap<String,String>();
try {
//准备工厂,进行配置(出于安全性考虑,当文件过大时每接收一点先缓存到临时文件中)
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(sizeThreshold);//设置临界点大小,当文件大小大于临界点大小时,将会产生临时文件
String tempPath2 = request.getSession().getServletContext().getRealPath(tempPath);
factory.setRepository(new File(tempPath2));//设置临时文件存放位置
//准备解析文件
ServletFileUpload upload = new ServletFileUpload(factory);//核心类
upload.setHeaderEncoding("utf-8");//设置文件名的编码,否则文件名含有中文时会出现乱码.如果不设置则使用request的编码
List<FileItem> allFileItem = upload.parseRequest(request);//解析request,获得文件项
for(FileItem fileItem : allFileItem){
if(fileItem.isFormField()){
//表单字段
String name = fileItem.getFieldName();
String value = fileItem.getString("utf-8");//参数为编码方式,不设置可能出现中文乱码
map.put(name, value);
}else{
//上传的文件
String fieldName = fileItem.getFieldName();//name属性
String fileName = fileItem.getName();//文件名称
fileName = getFileName(fileName);//处理文件名称
InputStream in = fileItem.getInputStream();//获得文件流
//将文件流保存到文件
String path = request.getSession().getServletContext().getRealPath(savePath);//保存路径
File file = new File(path,fileName);
OutputStream out = new FileOutputStream(file);
byte[] bytes = new byte[128 * 1024];
int len = 0;
while( (len = in.read(bytes)) > 0 ){
out.write(bytes,0,len);
}
in.close();
out.close();
fileItem.delete();//删除临时文件(如果有的话)
map.put(fieldName, fileName);
}
}
return map;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* 返回经过处理的文件名称,保证不重复
* @param fileName 要处理的文件名称
* @return 经过处理的文件名称
*/
private static String getFileName(String fileName){
fileName = fileName.substring(fileName.lastIndexOf("/") + 1);//处理兼容,因为ie8在xp下返回的是全路径
fileName = UUID.randomUUID().toString().replace("-", "") + "_" + fileName;//避免重复
return fileName;
}
}
上传文件示例
导入jar包和工具类
核心jar:commons-fileupload-1.2.2.jar   --> 来自commons-fileupload-1.2.2-bin.zip
依赖jar:commons-io-2.3.jar             --> 来自commons-io-2.3-bin.zip
工具类:自定义工具类FileUploadApacheUtils
在WEB-INF下创建tempFile和uploadFile文件夹
index.jsp
<form action="${pageContext.request.contextPath }/userServlet" method="post" enctype="multipart/form-data">
<input name="username" value="jack"><br>
<input type="file" name="uploadFile"><br>
<input type="submit" value="提交">
</form>
userServlet
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Map<String,String> map = FileUploadApacheUtils.fileUpload(request);
System.out.println(map);
}
上传文件请求
请求头
Content-Type: multipart/form-data; boundary=---------------------------7de32138c0540
请求体
-----------------------------7de32138c0540
Content-Disposition: form-data; name="username"
jack
-----------------------------7de32138c0540
Content-Disposition: form-data; name="password"
123
-----------------------------7de32138c0540
Content-Disposition: form-data; name="uploadFile1"; filename="123.txt"
Content-Type: text/plain
上传文件内容...
-----------------------------7de32138c0540
Content-Disposition: form-data; name="uploadFile2"; filename="456.txt"
Content-Type: text/plain
上传文件内容...
注意:上面上传了两个普通表单字段和两个文件.(请求体中的空行我去掉了)
请求头生成一串随机字符串,然后用此字符串将请求体的多个键-值分隔

文件下载
概述
服务器提供下载资源,当浏览器发送请求时,通知浏览器保存到本地
服务器:读取资源,发送到浏览器,通知浏览器下载
浏览器:下载
浏览器下载文件时,如果浏览器可以解析将直接显示,如果不能解析则提供下载。
通知浏览器总是进行下载:response.setHeader("content-disposition", "attachment;filename=文件名称");
文件中文显示乱码处理:value = new String(value.getBytes("GBK") , "ISO-8859-1");
示例
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String fileName = "图片.jpg";
//处理fileName中文乱码问题(响应头不支持中文)
//http协议进行iso8859-1编码,客户端进行gbk(操作系统默认编码)解码,所以要反着来一下
fileName = new String(fileName.getBytes("gbk"),"iso8859-1");
//通知浏览器内容类型为附件
response.setHeader("content-disposition", "attachment;filename=" + fileName);
//获得文件
InputStream in = request.getSession().getServletContext().getResourceAsStream("/图片.jpg");
//发送
OutputStream out = response.getOutputStream();
byte[] bytes = new byte[128 * 1024];
int len = 0;
while( (len = in.read(bytes))>0 ){
out.write(bytes,0,len);
}
in.close();
}
注意:处理文件名称中文乱码的代码通常放在过滤器中,处理图片名称含有中文的问题(向tomcat请求不到名称含有中文的图片)

servlet3.0
servlet3.0提供注解
@WebServlet, 用于取代servlet的配置web.xml <servlet>...配置内容
属性
name用来配置servlet名称,不写的话默认为当前类名
urlPatterns 和 value 作用一样,都用来配置servlet访问路径
例: @WebServlet("/one") 或 @WebServlet({"/one","/two"})
@WebFilter ,用于取代过滤器的配置 web.xml <filter>...配置内容,属性同上
@WebListener ,用于取代监听器的配置 <listener><listener-class>
@MultipartConfig,通知tomcat当前servlet将开启文件上传的处理,无属性
servlet3.0对文件上传进行支持
通过request.getPart(名称)获得上传内容,Part对象等价 commons FileItem
默认情况servlet不支持上传,需要在当前servlet上添加注解@MultipartConfig,无属性
注意:当使用@MultipartConfig注解时,request.getParameter()可以获得普通表单字段的值
工具类FileUploadServlet3Utils
public class FileUploadServlet3Utils {
/**
* 保存上传文件
* @param request 请求对象
* @param name input的name值
* @return 保存路径
*/
public static String saveUploadFile(HttpServletRequest request,String name){
String fileDir = "/WEB-INF/uploadFile";//保存文件夹
try {
// 获得上传文件内容对象
Part part = request.getPart(name);
if(part==null){
throw new RuntimeException("没有找到上传的文件");
}
// * 获得上传文件名称
String fileName = getFileName(part);
String savePath = fileDir+"/"+fileName;
// * 获得文件内容 --流
InputStream is = part.getInputStream();
// * 保存
String realSavePath = request.getServletContext().getRealPath(savePath);
FileOutputStream out = new FileOutputStream(new File(realSavePath));
byte[] buf = new byte[128*1024];
int len = -1;
while( (len = is.read(buf)) != -1 ){
out.write(buf, 0, len);
}
out.close();
is.close();
return savePath;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("保存上传文件失败");
}
}
/**
* 获得文件名称,保证不重复
* @param part
* @return
*/
private static String getFileName(Part part){
// * 获取文件名称
String headerValue = part.getHeader("Content-Disposition");
int beginIndex = headerValue.indexOf("filename=\"") + "filename=\"".length();
int endIndex = headerValue.length() -1;
String fileName = headerValue.substring(beginIndex, endIndex);
// * 处理文件名称 --浏览器兼容
fileName = fileName.substring(fileName.lastIndexOf("/") + 1);//处理兼容,因为ie8在xp下返回的是全路径
// * 处理文件名称 --不重复
fileName = UUID.randomUUID().toString().replace("-", "") + "_" + fileName;//避免重复
return fileName;
}
}
使用示例
在WEB-INF下创建uploadFile文件夹
index.jsp
<form action="${pageContext.request.contextPath }/userServlet" method="post" enctype="multipart/form-data">
<input name="username" value="jack"><br>
<input type="file" name="uploadFile"><br>
<input type="submit" value="提交">
</form>
userServlet
@MultipartConfig
public class UserServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String savePath = FileUploadServlet3Utils.saveUploadFile(request, "uploadFile");
System.out.println(savePath);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: