zoukankan      html  css  js  c++  java
  • 基础加强

    基础加强

    今日任务

    • 使用自定义注解完成仿@Test的作用.
    • 使用Servlet3.0完成文件上传.
    • 使用动态代理解决网站的字符集编码

    教学导航

    教学目标

    了解JDK中提供的三个注解

    会自定义注解及注解的反射.

    能够简单使用Servlet3.0

    掌握动态代理技术

    了解类加载器

    教学方法

    案例驱动法

    1.1 案例一:使用自定义注解完成@Test注解功能类似的效果:

    1.1.1 需求

    使用Junit是单元测试的工具.在一个类中使用 @Test 对程序中的方法进行测试.

    自定义一个注解@MyTest 也将这个注解加在类的方法上. 使这个方法得到执行.

    1.1.2 分析:

    1.1.2.1 技术分析:

    • 【注解】

    程序中有 注释 和注解

    * 注释:给开发人员.

    * 注解:给计算机看的.

     

    注解使用:学习框架支持注解开发.

    • JDK提供的注解】

    @Override :描述方法的重写.

    @SuppressWarnings :压制警告.

    @Deprecated :标记过时.

    • 自定义注解:

    定义一个类:class

    定义一个借口:interface

    定义一个枚举:enum

    定义一个注解:@interface

     

    【自定义注解案例】

    @interface MyAnno1{

     

    }

     

    带有属性的注解:

    @interface MyAnno2{

    int a() default 1;

    String b();

    // 注解属性的类型:基本数据类型,字符串类型String,Class,注解类型,枚举类型,以及以上类型的一维数组.

    // Date d();

    Class clazz();

    MyAnno3 m3(); // 注解

    Color c(); // 枚举

    String[] arrs();

     

    }

     

    @MyAnno4("aaa") // 如果属性名称为value 那么使用的时候 value可以省略(只出现这一个value的属性情况下).

    public class AnnotationDemo3 {

     

    }

     

    @interface MyAnno4{

    String value();

    int a() default 1;

    }

    1.1.2.2 步骤分析:

    定义一个测试类

    public class AnnotationDemo3 {

     

    @MyTest

    public void demo1(){

    System.out.println("demo1执行了...");

    }

     

    @MyTest

    public void demo2(){

    System.out.println("demo2执行了...");

    }

     

    public void demo3(){

    System.out.println("demo3执行了...");

    }

    }

    定义核心运行类:

    在核心运行类中有一个主函数:

    获得测试类中的所有的方法.

    获得每个方法,查看方法上是否有@MyTest注解.

    如果有这个注解,让这个方法执行.

    1.1.3 代码实现:

    通过元注解定义注解存在的阶段.

    * 元注解也是一个注解:修饰注解的 注解.

     

    自定义一个注解:

     

    核心运行类:

    public class CoreRunner {

     

    public static void main(String[] args) {

    // 反射:获得类的字节码对象.Class

    Class clazz = AnnotationDemo3.class;

    // 获得测试类中的所有的方法:

    Method[] methods = clazz.getMethods();

    // 遍历数组:

    for (Method method : methods) {

    // System.out.println(method.getName());

    // 判断方法上是否有@MyTest注解:

    boolean flag = method.isAnnotationPresent(MyTest.class);

    // System.out.println(method.getName()+"   "+flag);

    if(flag){

    // 让这个方法执行:

    try {

    method.invoke(clazz.newInstance(), null);

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

    }

    }

     

    }

    1.1.4 总结:

    使用注解完成JDBC工具类的编写:(了解)

    public class JDBCUtils {

    private static  String driverClass;

    private static  String url;

    private static  String username;

    private static  String password;

     

    @JDBCInfo

    public static Connection getConnection() throws Exception{

    // 反射:

    Class clazz = JDBCUtils.class;

     

    Method method = clazz.getMethod("getConnection", null);

     

    // 获得方法上的注解:

    JDBCInfo jdbcInfo = method.getAnnotation(JDBCInfo.class);

    driverClass = jdbcInfo.driverClass();

    url = jdbcInfo.url();

    username = jdbcInfo.username();

    password = jdbcInfo.password();

     

    Class.forName(driverClass);

    Connection conn = DriverManager.getConnection(url, username, password);

     

    return conn;

    }

    }

    1.2 案例二:使用Servlet3.0技术完成文件的上传:

    1.2.1 需求:

     

    1.2.2 分析:

    1.2.2.1 技术分析:

    Servlet3.0

    Servlet3.0 Servlet2.5

        * Servlet3.0需要运行在tomcat7以上的服务器中.

        * Servlet3.0以后web.xml就不是必须的.

    1.Servlet3.0支持注解开发.

    2.支持文件上传.

    Servlet3.0支持注解开发】

    使用@WebServlet替换web.xml中配置的Servlet

    @WebServlet(urlPatterns="/ServletDemo1",loadOnStartup=2,initParams=@WebInitParam(name="username",value="root"))

     

    使用@WebListener替换web.xml中监听器的配置:

    @WebListener

     

    使用@WebFilter替换web.xml中的过滤器的配置:

    @WebFilter(urlPatterns="/*")

    Servlet3.0的文件上传】

    • 文件上传:

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

    • 文件上传的要素:

    1.表单的提交的方式必须是POST.

    2.表单中必须有一个文件上传项:<input type=”file”>,而且文件上传项必须有name属性和值.

        * <input type=”file” name=”upload”/>

    3.表单的enctype属性的值必须是multipart/form-data

    • 文件上传的抓包分析:

    未修改enctype属性的时候:

     

    POST /WEB17_WEB/demo1/demo1.jsp HTTP/1.1

    Accept: text/html, application/xhtml+xml, */*

    X-HttpWatch-RID: 22325-10011

    Referer: http://localhost:8080/WEB17_WEB/demo1/demo1.jsp

    Accept-Language: zh-Hans-CN,zh-Hans;q=0.5

    User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko

    Content-Type: application/x-www-form-urlencoded

    Accept-Encoding: gzip, deflate

    Host: localhost:8080

    Content-Length: 47

    Connection: Keep-Alive

    Cache-Control: no-cache

    Cookie: JSESSIONID=99CD51DA9A47D29200168968AD983E9E

     

    upload=C%3A%5CUsers%5Capple%5CDesktop%5Caaa.txt

     

    已经修改了enctype属性:

    POST /WEB17_WEB/demo1/demo1.jsp HTTP/1.1

    Accept: text/html, application/xhtml+xml, */*

    X-HttpWatch-RID: 22325-10026

    Referer: http://localhost:8080/WEB17_WEB/demo1/demo1.jsp

    Accept-Language: zh-Hans-CN,zh-Hans;q=0.5

    User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko

    Content-Type: multipart/form-data; boundary=---------------------------7e02e526160b66

    Accept-Encoding: gzip, deflate

    Host: localhost:8080

    Content-Length: 224

    Connection: Keep-Alive

    Cache-Control: no-cache

    Cookie: JSESSIONID=99CD51DA9A47D29200168968AD983E9E

     

    -----------------------------7e02e526160b66

    Content-Disposition: form-data; name="upload"; filename="C:UsersappleDesktopaaa.txt"

    Content-Type: text/plain

     

    Hello shouyi

    -----------------------------7e02e526160b66—

    【文件上传的原理】

    根据分割线将请求体的部分分成几块:

    * 判断 每块是 普通项还是文件上传项.

        * 普通项:获得名称和值.

        * 文件上传项:获得文件名 和 文件内容输入流.

    【文件上传的技术】

    JspSmartUpload: jspSmartUpload组件是应用JSP进行B/S程序开发过程中经常使用的上传下载组件,它使用简单,方便。现在我又为其加上了下载中文名字的文件的支持,真个是如虎添翼,必将赢得更多开发者的青睐。-Model1年代的文件上传的工具.

    FileUpload Apache commons下面的一个子项目,用来实现Java环境下面的文件上传功能,与常见的SmartUpload齐名.应用在Model2年代了.

    Servlet3.0 :

    Struts2 :

     

    1.2.2.2 步骤分析:

    设计一个文件上传页面:

    提交到Servlet

    接收普通项:request.getParameter();

    接收上传项:Part

    通过Part对象中的方法完成文件的上传.

    1.2.3 代码实现

    package com.itheima.servlet;

     

    import java.io.FileOutputStream;

    import java.io.IOException;

    import java.io.InputStream;

    import java.io.OutputStream;

     

    import javax.servlet.ServletException;

    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;

     

    /**

     * 文件上传的Servlet

     */

    @WebServlet("/UploadServlet")

    @MultipartConfig

    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 desc = request.getParameter("desc");

    System.out.println("文件描述:"+desc);

    Part part = request.getPart("upload");

    // 获得上传的文件的大小

    long size = part.getSize();

    System.out.println("文件大小"+size);

    String type = part.getContentType();

    System.out.println("文件类型"+type); // text/plain  image/jpeg 

    String name = part.getName();

    System.out.println(name);

    // 获得文件名:

    String header = part.getHeader("Content-Disposition");

    System.out.println(header);

     

    int idx = header.lastIndexOf("filename="");

    String fileName = header.substring(idx+10, header.length()-1);

    System.out.println(fileName);

     

    // 获得文件内容:

    InputStream is = part.getInputStream();

     

    // 获得文件上传路径:

    String path = this.getServletContext().getRealPath("/upload");

     

    OutputStream os = new FileOutputStream(path+"/"+fileName);

    int len = 0;

    byte[] b = new byte[1024];

    while((len = is.read(b))!=-1){

    os.write(b, 0, len);

    }

    is.close();

    os.close();

     

    }

     

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    doGet(request, response);

    }

     

    }

    1.2.4 总结:

    1.2.4.1 文件名重名的问题:

    UUID随机产生一个文件名.

    1.2.4.2 文件上传的目录分离:

    按用户分 :一个用户创建一个或多个路径.

    按时间分 :按月,星期,天进行划分.

    按个数分 :一个路径中存3000个文件.

    按分离算法分 :按照一定的算法进行划分.

     

    1.3 案例三:使用动态代理的方式统一网站的字符集编码

    1.3.1 需求:

    在一个表单中分别使用getpost提交到Servlet中,在Servlet中直接调用getParameter方法解决中文乱码的问题!!!

    1.3.2 分析:

    1.3.2.1 技术分析:

    【动态代理】

    增强一个类中的某个方法.对程序进行扩展.Spring框架中AOP.

    什么是代理:

    【入门案例】

    class MyInvocationHandler implements InvocationHandler{

     

    private Waiter waiter;

     

    public MyInvocationHandler(Waiter waiter) {

    this.waiter = waiter;

    }

     

    @Override

    // 执行目标对象的任何一个方法 都相当于执行了invoke方法.

    /**

     * proxy:产生代理对象.

     * method:代表正在调用的方法.

     * Object[]:在调用的方法的参数.

     */

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    // System.out.println("aaaaa");

    // System.out.println(method.getName());

    if("server".equals(method.getName())){

    // 增强server.

    System.out.println("微笑...");

    return method.invoke(waiter, args);

    }else{

    // 不增强:

    return method.invoke(waiter, args);

    }

    // return null;

    }

     

    }

    1.3.3 代码实现:

    package com.itheima.encoding;

     

    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.annotation.WebFilter;

    import javax.servlet.http.HttpServletRequest;

     

    @WebFilter(urlPatterns="/*")

    public class GenericCharacterEncodingFilter implements Filter{

     

    @Override

    public void init(FilterConfig filterConfig) throws ServletException {

     

    }

     

    @Override

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

    throws IOException, ServletException {

    final HttpServletRequest req = (HttpServletRequest) request;

     

    // req产生代理对象:

    HttpServletRequest myReq = (HttpServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(),req.getClass().getInterfaces(), new InvocationHandler() {

     

    @Override

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    // 增强getParameter:

    if("getParameter".equals(method.getName())){

    // 增强.

    // 根据请求方式:

    String type = req.getMethod();

    if("get".equalsIgnoreCase(type)){

    // 调用原有的getParameter

    String value = (String)method.invoke(req, args);

    String s = new String(value.getBytes("ISO-8859-1"),"UTF-8");

    return s;

     

    }else if("post".equalsIgnoreCase(type)){

    req.setCharacterEncoding("UTF-8");

    return method.invoke(req, args);

    }

     

    }

    // 不增强:

    return method.invoke(req, args);

    }

    });

     

    chain.doFilter(myReq, response);

    }

     

    @Override

    public void destroy() {

     

    }

     

    }

     

    1.3.4 总结:

    1.3.4.1 【类的加载器:了解】

    类加载器就是将class文件加载到内存.

     

    JDK中提供的类加载器:

    * 引导/系统类加载器 Javajre7lib t.jar

    * 扩展类加载器 Javajre7libext*.jar

    * 应用类加载器 :自定义的类,类路径下的所有class文件.

     

    类的加载器的机制 :全盘委托机制.

    引导类加载器

        |

    扩展类加载器

        |

    应用类加载器

     

    class A{

        String s;

    }

     

    class文件由应用类加载器获得到,没有加载,向上一层委托向扩展类加载器委托,向上一层进行委托委托给引导类加载器.引导类加载器查看class哪些它负责,将自己负责的这个class进行加载.不是其负责的就向下传递扩展类加载器.扩展类加载器查看是否是其管理的class,如果是加载,不是就再向下到应用类加载器.

     

  • 相关阅读:
    变量定义和声明的差别(整理)
    堆栈指针理解
    HDU 4349 Xiao Ming&#39;s Hope
    iOS 8中CLLocationManager及MKMapView showUserLocation失败的解决的方法
    Ant命令行操作
    linux awk命令详细使用方法
    mysql 修改[取消]timestamp的自动更新
    cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第六步---炮台&amp;点击炮台加入英雄&amp;英雄升级
    SendMessage、PostMessage原理
    poj 2104 K-th Number 主席树+超级详细解释
  • 原文地址:https://www.cnblogs.com/nextgg/p/7642852.html
Copyright © 2011-2022 走看看