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) 访问集合 访问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.Serializable接口 注册监听器(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); } }
Servlet-JSP相关
最新推荐文章于 2021-11-26 16:25:28 发布