day22-JAVA基础增强(注解开发/servlet3.0)

来源:互联网 发布:淘宝买家具运费怎么办 编辑:程序博客网 时间:2024/06/03 21:03
1.注解
   Jdk常见注解    自定义注解    完成类似juint测试案例(注解+反射)
2.servlet3.0(开发的快但是不容易维护,市场小)
   Servlet3.0的特性    创建一个servlet   过滤器   监听器  

文件上传(servlet3.0的技术)有很多种技术

【注解的概述】

注解和注释区别:

* 注释:给程序员看的.

* 注解:给虚拟机看的.(让虚拟机看到程序中的注解,注解代表程序的一些特殊的功能.)

 

【JDK中提供的注解】

@Override            :描述子类重写父类的方法:

* JDK1.5版本的时候该注解只能应用在 类的继承上.

* JDK1.6版本的时候该注解可以应用在类的实现上.

在引用别人写的代码时候可能因为版本问题而出现该类问题,注意这种报错形式.

@SuppressWarnings      :压制警告. @SuppressWarnings(“all”)

@Deprecated                :描述方法过时.


JDK版本的查看:

项目属性-->java compiler


【自定义注解】

自定义注解:

* 定义类       :class

* 定义接口    :interface

* 定义枚举    :enum

* 定义注解    :@interface  定义在类的外面

 

代码实现:

* 定义一个注解:名称是Anno1

@interface Anno1{}


定义注解的属性:

 Invalid type Date for the annotation attributeAnno2.d; only primitive type, String, Class,annotation, enumeration are permitted or 1-dimensional arrays thereof

* 注解的属性的类型:

    * 基本数据类型:

    * String类型:

    * Class类型:

* 注解类型:

    * 枚举类型:

    * 以上类型的一维数组:

* 代码实现:

/** 定义一个带有属性的注解:Anno2

 */使用方式:@ Anno2(a=2,b=true,s=”dsf”,…)

@interface Anno2{       int a();       boolean b() default false;       String s();       // Date d();       Class c();       Anno1 anno1();       Color color();       String[] arrs();}


***** 特殊的属性名称:value

    * 如果使用注解的时候,只出现了value属性,value属性可以省略的.


模拟@Test的功能实现代码:

编写自定义注解的测试类:

public class AnnotationDemo1{         @MyTest         public void demo1(){                   System.out.println("11111111111");         }         @MyTest         public void demo2(){                   System.out.println("22222222222");         }         public void demo3(){                   System.out.println("33333333333333");         }}

①自定义注解类MyTest -->②定义核心运行类

 

①自定义注解类MyTest;

    * 自定义注解默认存在于源码阶段,需要让注解存在的时间更长.使用元注解:(只用于修饰其他的注解) @Retention(value=RetentionPolicy.RUNTIME).

@Retention(value=RetentionPolicy.RUNTIME)public @interface MyTest { }

②定义核心运行类.

我的理解:要把我定义的注解实现@Test的运行效果就需要使有注解的地方自动执行,所以用反射技术就可以自动实现.所以要定义这个核心运行类.

    *获得测试类的Class

    *获得Class中的所有方法.

    *遍历得到每个方法.

* 判断方法上有MyTest注解,就执行该方法.

(但此时method.isAnnotationPresent(MyTest.class)有缺陷需要改进)

        * 自定义注解默认存在于源码阶段,需要让注解存在的时间更长.使用元注解:(只用于修饰其他的注解)

 

* 核心运行类:
public class CoreRunner {public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {// 1.获得测试类的Class:Class clazz = AnnotationDemo1.class;// 2.获得Class中的所有的方法: 规定了测试的方法必须是public.Method[] methods = clazz.getMethods();// 3.遍历每个方法:for(Method method:methods){boolean flag = method.isAnnotationPresent(MyTest.class);//判断测试类的方法上是否有自定义的注解@MyTestif(flag){// 说明方法上有@MyTest注解:就执行method.invoke(clazz.newInstance(), null); }}}}

注解所存在的阶段通过给自定义注解设置元注解来延长(为runtime):



【Servlet3.0】

Servlet3.0与Servlet2.5提供了三个新特性:
* 注解开发 :方便
* 文件上传 :有些API不是特别全.
* 异步请求


【Servlet3.0的注解开发】

@WebServlet
@WebListener
@WebFilter

@WebServlet(urlPatterns="/ServletDemo1",loadOnStartup=2,initParams={@WebInitParam(name="username",value="root"),@WebInitParam(name="password",value="123")})public class ServletDemo1 extends HttpServlet{@WebListenerpublic class MyServletContextListener implements ServletContextListener{@WebFilter(urlPatterns="/*",asyncSupported=true)public class FilterDemo1 implements Filter{
过滤的执行顺序按照类名首字母排序A-Z先后执行


【文件上传的概述】

文件上传:
* 指的是将本地的文件写到服务器上.


文件上传技术:
* Servlet3.0       :注解开发,文件上传,异步请求.
* JSPSmartUpload :嵌入到JSP中完成文件上传.主要用于Model1年代的.
* FileUpload :Apache的文件上传组件.(struct2的底层)
* Struts2 :底层是FileUpload.


文件上传的三要素:
* 表单的提交的方式必须是POST.(get有大小限制)
* 表单中需要有文件上传的表单元素:这个元素这个元素必须有name属性和值:
<input type=”file” name=”upload”>
* 表单的enctype属性的值必须是multipart/form-data.
进行文件上传的抓包分析得出:
没有设置enctype属性的时候:只能获得文件的名称,而没有文件内容.
设置enctype属性为multipart/form-data:获得到文件名及文件内容.


Application/x-www-form-urlencoded  :正常的表单数据
Multipart/form-data :文件上传包含普通表单
Text/plain :发邮件用的文件类型.


使用Servlet3.0完成一个文件上传的功能:

【步骤一】:.
【步骤二】:点击提交,提交到中.
【步骤三】:在Servlet中接收参数.
【步骤四】:获得服务器的文件上传的路径.
【步骤五】:通过流写到该路径下就OK了.
①设计一个文件上传页面-->②文件上传的Servlet-->③对文件重名与目录分级的处理类编写
②接收文件的数据,获得服务器的文件上传的路径.通过流写到该路径下就OK了.


①设计一个文件上传页面

<body><h1>文件上传的页面</h1><form action="${ pageContext.request.contextPath }/UploadServlet" method="post" enctype="multipart/form-data"><table border="1" width="600"><tr><td>文件描述</td><td><input type="text" name="filedesc"></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>

②文件上传的Servlet

@WebServlet("/UploadServlet")   //servlet3.0必须的配置@MultipartConfig      //servlet3.0中特有的一些方法才能够使用public class UploadServlet extends HttpServlet {private static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 接收文件描述:request.setCharacterEncoding("UTF-8");String filedesc = request.getParameter("filedesc");System.out.println("文件描述"+filedesc);// 接收文件:得到name为upload的上传的文件数据. Part part = request.getPart("upload");//获得文件上传部分数据的专用方法,封装到servlet3.0中一个特有的对象Part中.导的是javax.servlet.http的包.long size = part.getSize();// 获得文件大小: System.out.println("文件大小:"+size);String name = part.getName();    //是upload而不是真的文件名System.out.println("文件表单中的name属性的名称"+name); // 获得文件名:得自己截取String header = part.getHeader("Content-Disposition");//获得到含文件名的头int idx = header.lastIndexOf("filename=\"");//其中\”用来转义引号.找到名位置String fileName = header.substring(idx+10, header.length()-1);System.out.println("文件名:"+fileName);// 获得文件内容:InputStream is = part.getInputStream();// 获得upload的路径:String path = this.getServletContext().getRealPath("/upload");//提前建好文件夹// 获得文件的唯一文件名:String uuidFileName = UUIDUtils.getUUIDFileName(fileName);String realPath = path+UploadUtils.getPath(uuidFileName);File file = new File(realPath);if(!file.exists()){file.mkdirs();}OutputStream os = new FileOutputStream(realPath+"/"+uuidFileName);byte[] b = new byte[1024];int len = 0;while((len = is.read(b))!=-1){os.write(b, 0, len);}is.close();os.close();}


③对文件重名与目录分级的处理类编写

文件名重名.

使用随机的唯一文件名:

* 使用UUID作为随机的文件名.

先创建好UUID的工具类:

public class UUIDUtils {         public static StringgetUUID(){                   return UUID.randomUUID().toString().replace("-", "");         }         public static StringgetUUIDFileName(String fileName){                   return UUID.randomUUID().toString().replace("-", "")+"_"+fileName;         }}

一个目录下存放的文件过多.

一个目录下文件过多,导致打开都很慢,更别说是读写操作.

目录分离:

* 按时间分    :一个月一个目录,一个星期一个目录,一天一个目录

* 按数量分    :一个目录下存5000个文件,创建一个新的目录,再去存放.

* 按用户分    :为每个用户创建一个单独目录存放文件.

* 按目录分离算法分         :

    * 使用唯一文件名.hashCode(); --得到一个代表当前这个文件的int类型值.

    * int类型占4个字节32.可以让hashCode&0xf;得到一个int,用这个int值作为一级目录.

* hashCode右移4 &0xf ;得到一个int,用这个int值作为二级目录.依次类推.

 

public class UploadUtils {         public static StringgetPath(String uuidFileName){                   // 使用唯一文件名.hashCode();                   int code1 = uuidFileName.hashCode();                   int d1 = code1 & 0xf; // 0x是16进制,获得到1级目录.把二进制转为十进制                   int code2 = code1 >>> 4;  //>>右移,>>>为无符号右移                   int d2 = code2 & 0xf; // 获得到2级目录.                   return "/"+d1+"/"+d2;         }}

按照这个逻辑以此类推code1是个int是4个字节,一个字节8bit,所以code1可以有8个4位的二进制,所以可以有8级目录.

然后在文件上传的servlet保存目录中去相应的改进.

 

同理可以按这个逻辑再在前面拼接上本地存放文件的目录就可以拿到指定的文件了.


Servlet3.0支持异步请求:

过滤器如果过滤的内容中有异步的也必须加上异步配置.