JavaWeb开发知识总结(annotation,Servlet3.0,文件上传,动态代理)
来源:互联网 发布:钢结构厂房起脊算法 编辑:程序博客网 时间:2024/05/29 11:50
JavaWeb开发知识总结(annotation,Servlet3.0,文件上传,动态代理)
1. annotation概述
annotation:注解,代表程序的一些特殊的功能,注解是由虚拟机进行处理的。
JDK中提供的常用的注解:
# @Override :描述子类重写父类的方法: * JDK1.5版本中,该注解只能应用在类的继承上. * JDK1.6版本中,该注解可以应用在类的实现上(实现接口).# @SuppressWarnings :压制警告,参数是all是压制所有的警告.# @Deprecated :描述方法过时,标记方法过时.
自定义注解:使用@interface
关键声明
格式:public @interface 注解名称{ 内容 }
注解的属性定义:
# 注解定义时需加上`()`,如: @interface Anno { int a(); boolean b() default false; }# 定义属性时:可以使用default关键字声明属性的默认值# 注解的属性的数据类型: 1. 基本数据类型:primitive type 2. String类型:String 3. Class类型:Class 4. 注解类型:annotation 5. 枚举类型:enumeration 6. 以上类型的一维数组:# 特殊的属性名称:value * 如果使用注解的时候,只出现了value属性,value属性可以省略,但当出现多个属性时,value属性名不能省略
注解的存在阶段:
# Java类的状态:源代码阶段-->Class阶段-->运行阶段 源代码阶段 Class阶段 运行阶段.java源文件 --编译--> .class --加载--> JVM中运行# 自定义的注解只存在与源代码阶段,编译后就不存在了,可以通过JDK提供的元注解来增大自定义注解的存在阶段:1. 源代码阶段:@Retention(value = RetentionPolicy.SOURCE)2. Class阶段:@Retention(value = RetentionPolicy.CLASS)3. 运行阶段:@Retention(value = RetentionPolicy.RUNTIME)
案例:自定义注解完成简单的注解单元测试的功能
package com.annotation;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;/** * 自定义注解 MyTest.java */@Retention(value=RetentionPolicy.RUNTIME) // 设置自定义注解运行阶段public @interface MyTest {}/** * 运行的核心类 CoreRunner.java * 和单元测试的原理相同,均需要一个程序运行的主方法 * 获取要进行单元测试的类的Class对象,通过反射获取该类的所有的方法 * 遍历所有的方法,如果方法上有注解,则通过反射执行该方法即可 */public class CoreRunner { public static void main(String[] args) throws Exception { /** * 获得测试类的Class. * 获得Class中的所有的方法. * 遍历每个方法,查看每个方法上是否有MyTest注解. * 有MyTest注解,这个方法就执行. */ // 1.获得测试类的Class: Class clazz = AnnotationDemo1.class; // 2.获得Class中的所有的方法:规定了测试的方法必须是public Method[] methods = clazz.getMethods(); // 3.遍历每个方法: for(Method method:methods){ // 获取当前的方法是否含有MyTest注解 boolean flag = method.isAnnotationPresent(MyTest.class); if(flag){ // 说明方法上有MyTest注解,执行方法 method.invoke(clazz.newInstance(), null); } } }}
2. Servlet 3.0
Servlet3.0和Servlet2.5的区别:
# Servlet3.0和Servlet2.5相比提供了三个特性:1. 注解开发:可以取代web.xml的配置文件 * @WebServlet:Servlet的注解 * @WebListener:监听器的注解 * @WebFilter:过滤的注解2. 文件上传:没有提供获取上传的文件名等相关的API3. 异步请求:本质是开启新的线程进行处理请求
注解开发的原理:
// Servlet2.5中web.xml配置文件配置Servlet<servlet> <servlet-name>servlet名称</servlet-name> <servlet-class>servlet的完全限定名</servlet-class></servlet><servlet-mapping> <servlet-name>servlet名称</servlet-name> <url-pattern>servlet的访问路径</url-pattern></servlet-mapping>// Servlet3.0中使用注解@WebServlet(urlPatterns="Servlet的访问路径") 在定义Servlet时添加注解,相当于是配置文件的中访问路径public class Servlet名称 extends HttpServlet {...}
3. 文件上传
文件上传要素:必须同时满足
# 文件上传的要素: 三个条件必须满足1. 表单的提交的方式必须是POST. (由于Get方式有数据大小的限制,不使用get方式上传数据)2. 表单中需要有文件上传的表单元素:这个元素必须有name属性和值:<input type="file" name="upload">3. 表单的enctype属性的值必须是multipart/form-data. (enctype的默认值是:"application/x-www-form-urlencoded",该默认值在后台中只能获取文件的名称,无法获取文件内容)
文件上传的技术:
# 文件上传技术: Servlet2.5不支持文件上传* Servlet3.0 :比2.5版本增加的功能:注解开发,文件上传,异步请求.* JSPSmartUpload :嵌入到JSP中完成文件上传.主要用于(jsp+javabean开发模式)的.* FileUpload :Apache的文件上传组件.* Struts2 :底层是FileUpload.
使用Servlet3.0实现文件上传:
注意事项(重点):
# form表单的设为enctype="multipart/form-data"后,Servlet中getParameter()等获取参数的方法无效,需要在Servlet上添加 @MultipartConfig 注解# 上传的文件的信息不能通过getParameter()等获取参数的方法获取,需要使用getPart()方法进行操作
文件上传存在的问题:
# 文件的重名问题:解决方法:1. 使用UUID生成随机的字符串作为文件名,数据库中存储的是文件原始名称和真实文件存储路径的映射;2. 使用时间戳+原始文件名作为存储的文件名,数据库中存储的是文件原始名称和真实文件存储路径的映射.# 同一目录下存储文件过多:解决方法:1. 按时间分:一个月一个目录,一个星期一个目录,一天一个目录2. 按数量分:一个目录下存5000个文件,创建一个新的目录,再去存放.3. 按用户分:为每个用户创建一个单独目录 存放文件.4. 按目录分离算法分: * 使用唯一文件名.hashCode(); -- 得到一个代表当前这个文件的int类型值. * int类型占4个字节32位.可以让hashCode值&0xf; 得到一个int值,用这个int值作为一级目录. * 让hashCode右移4位 &0xf ;得到一个int值,用这个int值作为二级目录.依次类推.
案例实现:
<!--fileupload.jsp--><% @ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>文件上传</title></head><body><h1>文件上传</h1><form action="${ pageContext.request.contextPath }/FileUploadServlet" method="post" enctype="multipart/form-data"> <table border="1"> <tr> <td>文件描述</td> <td> <textarea rows="4" cols="20" name="filedesc"></textarea> </td> </tr> <tr> <td>文件上传</td> <td> <input type="file" name="upload" /> </td> </tr> <tr> <td colspan="2"> <input type="submit" value="上传"/> </td> </tr> </table></form></body></html>
package com.itheima.servlet;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import javax.servlet.ServletException;import javax.servlet.ServletInputStream;import javax.servlet.annotation.MultipartConfig;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.Part;import com.itheima.utils.UpLoadUtils;/** * 文件上传的Servlet FileUploadServlet.java */@WebServlet(urlPatterns="/FileUploadServlet")@MultipartConfig // 该注解是将传统的获取参数的方法进行封装public class FileUploadServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置request缓冲区的编码,防止中文数据乱码 request.setCharacterEncoding("UTF-8"); // 获取文件的描述信息 String filedesc = request.getParameter("filedesc"); // 获取代表文件部分的对象 Part part = request.getPart("upload"); // 获取文件大小 // int size = part.getSize(); // 获取表单中该文件的input标签的name属性值 // String name = part.getName(); // Servlet3.0没有提供获取上传文件名的方法,需要从part的头信息中进行截取 // 获取请求头的Content-Disposition字段值 // 获取的文件的格式是:form-data; name="upload"; filename="文件名" String header = part.getHeader("Content-Disposition"); // 分割头信息获取文件名 int lindex = header.lastIndexOf("\""); // 获取最后一个双引号的索引 int findex = header.substring(0, lindex).lastIndexOf("\""); String filename = header.substring(findex + 1, lindex); // 定义在服务器存储文件的根目录 String realPath = request.getServletContext().getRealPath("/upload"); File file = new File(realPath); // 存储文件的目录不存在则创建目录 if(!file.exists()) { file.mkdir(); } // 获取存储时的文件名,防止文件的重名 String realFileName = UpLoadUtils.setFileName(filename); // 获取文件存储路径,防止同一目录下文件过多,使用目录分离算法建立存储目录 String storePath = UpLoadUtils.getPath(); // 根据文件存储的根目录和存储路径获取存储的完全路径 file = new File(realPath+storePath); // 如果文件存储的目录不存在则创建 if(!file.exists()) { file.mkdirs(); } // 获取要存储文件的对象 file = new File(file,realFileName); // 存储文件,使用IO流读写文件,上传文件信息存储在part中 // 是从part中获取字节输入流对象,不是获取request中的输入流对象 InputStream is = part.getInputStream(); OutputStream os = new FileOutputStream(file); // 读取文件并保存到指定目录 byte[] bys = new byte[1024]; int len = 0; while((len = is.read(bys)) != -1) { os.write(bys, 0, len); } // 释放资源 os.close(); // is.close(); 输入流资源是从part中获取的,可以不用释放,part会进行管理 // 给出提示 response.setContentType("text/html;charset=UTF-8"); response.getWriter().println("<h1>文件上传成功</h1>"); }}
package com.itheima.utils;import java.text.SimpleDateFormat;import java.util.Date;/** * 文件上传的工具类 UpLoadUtils.java */public class UpLoadUtils { /** * 根据文件名称获取文件保存的目录 * 按照时间进行分离目录 * 存储路径格式:yyyy-MM-dd/HH-mm-ss * @param filename 文件名 * @return 返回文件的存储路径 */ public static String getPath() { // 获取当前日期 Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd#HH-mm-ss"); String format = sdf.format(date); return "/"+format.split("#")[0]+"/"+format.split("#")[1]; } /** * 根据时间生成文件的名称 * 防止文件重名 * 新文件名格式:yyyy_MM_dd_HH_mm_ss_SS-原始文件名 * @param filename 文件名称 * @return 返回文件的新的名称 */ public static String setFileName(String filename) { Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss_SS"); String format = sdf.format(date); return format+"-"+filename; }}
4. 动态代理
代理模式:是java开发的设计模式,其特点是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及委托类处理消息后再次处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用自定义类的相关方法,实现对委托类的代理访问。 按照代理的创建时期,代理类可以分为两种。
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:动态代理类与普通类的唯一区别就是其字节码是由 JVM 在运行时动态生成的而非预存在于任何一个 .class 文件中。
Java的JDK中提供创建动态代理类API,当时只能创建针对接口的动态代理类。创建动态代理的要求是:被代理的类实现了接口。
4.1 Java中动态代理类和接口
1. Java.lang.reflect.Proxy:动态代理类,提供一组静态方法为一组接口动态的生成子类对象和代理类
2. java.lang.reflect.InvocationHandler:调用处理器接口,实现invoke方法,用于实现对于被代理类的代理访问
// 该接口就只有一个方法,该方法是用户处理被代理类的访问控制/** * 该方法负责集中处理动态代理类上的所有方法调用(就是对被代理类的访问进行控制) * proxy:代理类实例 * method:被调用的方法对象(就是被代理类中的方法) * args:调用该方法的参数*/public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
4.2 动态代理的使用步骤(增强已知类)
- 创建需要被代理的类的对象;
- 创建动态代理类对象;
- 实现对被代理类对象访问控制的invoke方法。
案例:创建Servlet访问的统一的字符集编码过滤器,解决获取参数的GET和POST方式的中文乱码问题
import java.io.IOException;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;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;/** * 统一的字符集编码过滤器 * @ClassName: CharacterEncodingFilter * @Description:(统一的字符集编码过滤器) */public class CharacterEncodingFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 1.获取被代理类的对象 final HttpServletRequest hsrequest = (HttpServletRequest) request; // 2.创建动态代理对象 HttpServletRequest myrequest = (HttpServletRequest) Proxy.newProxyInstance(hsrequest.getClass().getClassLoader(), hsrequest.getClass().getInterfaces(), new InvocationHandler() { @Override // 3.实现invoke方法,实现对被代理类对象的访问的控制 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 对request对象的getParameter方法的get和post方法获取参数进行字符集编码的处理 // 获取方法的名称 String methodName = method.getName(); // 当方法名时getParameter时,进行增强 if("getParameter".equals(methodName)) { // 获取请求的方式 String reqMethod = hsrequest.getMethod(); // 当是get方式请求 if("get".equalsIgnoreCase(reqMethod)) { // get方式需将其中的值取出,进行编码转换 // 先调用原始的方法获取其中的值,然后进行编码的转换 String value = (String) method.invoke(hsrequest, args); return new String(value.getBytes("ISO-8859-1"),"UTF-8"); } else if("post".equalsIgnoreCase(reqMethod)) { // 当请求是post方式,post方式只需设置request的缓冲区的编码即可 hsrequest.setCharacterEncoding("UTF-8"); // 原始调用原始的获取参数的方法 return method.invoke(hsrequest, args); } } // 针对request中其余的方法执行原有的调用即可 return method.invoke(hsrequest, args); } }); // 4.将请求放行,注意放行的是代理对象 chain.doFilter(myrequest, response); } @Override public void destroy() { }}// 字符集过滤器需要在项目的web.xml中进行配置 <!-- 配置字符集过滤器 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>com.filter.CharacterEncodingFilter</filter-class> </filter> <!-- 配置过滤器的映射 --> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
4.3 类加载器
java.lang.ClassLoader:类加载器,将类的字节码加载到JVM中并为创建类对象,然后该类才能被使用。Proxy类与普通类的唯一区别就是其字节码是由 JVM 在运行时动态生成的而非预存在于任何一个 .class 文件中。每次生成动态代理类对象时都需要指定一个类加载器对象:newProxyInstance()方法第一个参数。
Java中类加载器:
# Java中类加载器分为三类:加载器间是层级关系,不是子父类关系1. 引导类加载器:负责加载本地环境的JDK中/jre/lib/rt.jar,该包是Java的核心api |2. 扩展类加载器:负责加载本地环境中JDK中/jre/lib/ext/\*.jar,该包是Java的扩展API |3. 应用类加载器:负责加载自定义类路径下所有的class文件# Java中为保证类只被加载一次:使用的是类加载器的全盘委托机制# 全盘委托机制原理:所有的类加载都要先经过`应用类加载器`,`应用类加载器`获得所有的class文件后不进行操作直接向`扩展类加载器`传递这些class文件,`扩展类加载器`拿到所有的class文件后不进行操作直接向`引导类加载器`传递这些class文件;`引导类加载器`获取所有的class文件后查找其中属于自己负责加载的class文件进行加载,将剩余的class文件传递给`扩展类加载器`,`扩展类加载器`拿到class文件后只加载属于自己负责加载的class文件进行加载,将剩余的class文件传递给`应用类加载器`,`应用类加载器`获取剩余的class文件进行全部的加载。这种机制保证了每个class文件只被加载一次。
- JavaWeb开发知识总结(annotation,Servlet3.0,文件上传,动态代理)
- JavaWeb开发知识总结(七)-(struts2_文件上传_Ajax)
- JavaWeb之使用Servlet3.0实现文件上传案例
- servlet3.0上传文件
- servlet3.0文件上传
- Servlet3.0文件上传
- servlet3.0 文件上传
- Servlet3.0学习总结(三)——基于Servlet3.0的文件上传
- Servlet3.0学习总结(三)——基于Servlet3.0的文件上传
- Servlet3.0学习总结(三)——基于Servlet3.0的文件上传
- Servlet3.0学习总结(三)——基于Servlet3.0的文件上传
- Servlet3.0学习总结(三)——基于Servlet3.0的文件上传
- Servlet3.0学习总结(三)——基于Servlet3.0的文件上传
- Servlet3.0的文件上传
- Servlet3.0现实文件上传
- servlet3.0多文件上传
- Servlet3.0 上传文件实例
- 【Demo】Servlet3.0 上传文件
- PAT1006 Sign In and Sign Out
- 人家的第一次
- Python:合并两个numpy矩阵
- 比较对象值
- 设计模式——创建型之使用工厂方法模式灵活自由创建你的产品族和方案(二)
- JavaWeb开发知识总结(annotation,Servlet3.0,文件上传,动态代理)
- 自定义 MyHorizontalScrollView
- 常用的C++11特性(面试易考)
- pgbouncer连接greenplum单机
- Android端运行Tensorflow的demo去分类自己的数据集
- Java回炉重造(三)使用Apache Commons Text库计算文本相似性:jaccard相似系数、余弦相似度
- hdoj1053 Entropy(哈夫曼编码)
- 0526 HDU#5477&G2n#A-A Sweet Journey
- C语言课设总结