当前位置: 代码迷 >> 综合 >> 17-Javaweb-注解 & servlet3.0 & 类加载器 & 动态代理
  详细解决方案

17-Javaweb-注解 & servlet3.0 & 类加载器 & 动态代理

热度:77   发布时间:2024-01-31 03:37:15.0

 

目录

一、案例1-模拟junit测试

1-1 注解

1-1 java中3个注解(理解)

1-2 自定义注解(理解)

1-2-1 注解属性

1-2-2 注解属性类型

1-2-3 赋值的格式

1-2-4 元注解:(理解)

1-3 步骤分析:(了解)

1-3-1 定义一个注解 @MyTest

1-3-2 在一个测试类 MyTestTest 上的添加几个方法

1-3-3 在另一个有主方法的类上添加main方法

1-4 案例扩展- 通过注解获取连接的工具类

1-5 步骤分析

1-5-1 自定义一个注解JDBCInfo

1-5-2 在jdbcutils工具类中提供一个getConnection,在方法上面添加一个注解 @JDBCInfo(...) 

1-5-3 运行的时候可以通过getConnection获取一个连接

二、案例2-完成文件上传

2-1 servlet3.0

2-2 文件上传

2-2-1 浏览器端的要求

2-2-2 服务器端的要求

 2-2-3 案例简单实现

2-3 上传注意的问题

2-3-1 名字重复 随机名称

2-3-2 文件安全

2-3-3 文件存放目录

 2-3-4 文件上传工具类

 2-3-5 文件上传完善

2-4 类加载器:(了解)

2-4-1 类加载

2-4-2 类加载器层次结构

2-4-5 全盘负责委托机制

三、案例3-统一编码

3-1 静态代理书写步骤

3-2 动态代理

3-2-1 方式1-Proxy类

3-2-2 方式2-cglib

3-2-3 动态的在内存中创建一个代理对象    

3-3 步骤分析

总结


注解:了解注解,可以使用注解
servlet3.0:体验下注解,完成文件上传
类加载器(了解)
动态代理(★):加强方法

  • 一、案例1-模拟junit测试

需求:
在一个类的方法中添加一个@MyTest,在另一个类的main方法中,就可以执行带有@MyTest的方法
技术分析:
注解
反射

  • 1-1 注解

    jdk5之后提供了一个特性,和类 接口同级
格式:
@interface 注解名{}
作用:
编译检查
替代配置文件
定义注解(元注解:注解上的注解)
分析代码(用到反射)

  • 1-1 java中3个注解(理解)

  1.     @Override:声明该方法是从父类上继承过来的,执行编译期的检查
  2.     @SuppressWarnings:抑制警告 值有好多,只需要知道一个 all  抑制所有的警告 
      @SuppressWarnings("all")
  3.     @Deprecated:声明 该方法不赞成使用(已过时,有bug)
  • 1-2 自定义注解(理解)

  • 1-2-1 注解属性

    注解本质就是一个接口,接口中可以有常量和抽象方法
抽象方法在注解中就称之为注解属性

  • 1-2-2 注解属性类型

  1.     基本类型
  2.     String
  3.     Class
  4.     Annotation
  5.     Enum:枚举(严格的类,不能new, 只能使用已经定义好的属性  private Color RED; )
     Color RED();
  6.     以上类型对应的一维数组
public @interface MyAnnotation2 {//注解属性int i();String s();//Date d();String[] ss();Class cl();MyAnnotation1 m1();Color RED();}

 

注意:
一旦注解有属性了,使用注解的时候必须赋值,(除非这个注解属性有默认值)

  • 1-2-3 赋值的格式

    @注解名(属性名=属性值)
若注解类型为数组,且只有一个值的时候,可以有两种写法
方式1:
属性名 = { 值 }               ss = {"qew", "123"}
方式2:
属性名=属性值              ss = "123"
若属性名为value的时候,且只需要为这个value属性赋值的时候,value可以省略

//@MyAnnotaion3(i = 0)
@MyAnnotaion3("")
public class Demo3 {}public @interface MyAnnotaion3 {//int i();//String s();/*** int i();String s();String[] ss();*/String value();
}

 

  • 1-2-4 元注解:(理解)

    定义在注解上的注解
 @Retention  规定注解保留到什么阶段  值为RetentionPolicy的三个枚举值
SOURCE:只在代码中保留,在字节码文件中就删除了(默认
CLASS:在代码和字节码文件中保留
RUNTIME:所有阶段都保留   (配置文件)           
@Target 规定注解作用在什么上面     值为ElementType的枚举值
TYPE:作用在类 接口 等上面
METHOD:作用方法上面
FIELD:作用字段上面   

  • 1-3 步骤分析:(了解)

  • 1-3-1 定义一个注解 @MyTest

    //注解在运行时保留
    @Retention(RetentionPolicy.RUNTIME)//注解只能作用在方法上
    @Target(ElementType.METHOD)public @interface MyTest {}
    

     

  • 1-3-2 在一个测试类 MyTestTest 上的添加几个方法

    在方法上添加@MyTest    

public class MyTestTest {@MyTestpublic void f1(){System.out.println("f1方法执行了~~~~");}public void f2(){System.out.println("f2方法执行了~~~~");}@MyTestpublic void f3(){System.out.println("f3方法执行了~~~~");}
}

 

  • 1-3-3 在另一个有主方法的类上添加main方法

    运行main方法的时候,需要将带有 @MyTest注解的方法执行              

//判断方法是否有指定的注解 

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

package com.itheima.a_annotation;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class MainTest {/*public static void main(String[] args) {//运行这个类的时候 需要将 测试类中带有@mytest所有方法执行//获取字节码对象Class clazz=MyTestTest.class;//获取所有的方法Method[] arr = clazz.getMethods();//让方法执行for (Method m : arr) {//打印所有方法的名称System.out.println(m.getName());}}*/public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {//运行这个类的时候 需要将 测试类中带有@mytest所有方法执行//1 获取字节码对象Class clazz=MyTestTest.class;//2 获取所有的方法Method[] arr = clazz.getMethods();//3 让带有注解的方法执行for (Method m : arr) {//获取有注解的方法//判断方法是否有指定的注解 boolean flag=m.isAnnotationPresent(MyTest.class);if(flag){//System.out.println(m.getName());m.invoke(clazz.newInstance());}}}
}

 

  • 1-4 案例扩展- 通过注解获取连接的工具类

    获取连接的工具类,通过注解,配置四个参数

  • 1-5 步骤分析

  • 1-5-1 自定义一个注解JDBCInfo

    添加元注解:
程序运行的时候使用  @Retention
只能作用在方法上      @Target
添加注解属性
String driverClass() default "com.mysql.jdbc.Driver";   //添加默认值
String url();
String username() default "root";
String password();

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface JdbcInfo {String driverClass() default "com.mysql.jdbc.Driver";String url();String user() default "root";String password() default "root";}

 

  • 1-5-2 在jdbcutils工具类中提供一个getConnection,在方法上面添加一个注解 @JDBCInfo(...) 

    getConnection方法需要进行的操作:获取注解上的四个属性值

  •         获取字节码文件
  •         获取该方法上的注解
//jdbcinfo注解 获取
JdbcInfo info = m.getAnnotation(JdbcInfo.class);
  •         获取注解的值
//4.获取注解四个属性
String driverClass = info.driverClass();
String url = info.url();
String user = info.user();
String password = info.password();
public class JdbcUtils {@JdbcInfo(url = "jdbc:mysql://localhost:3306/day16",password="1234")public static Connection getConnection() throws Exception{//1.获取字节码文件Class clazz=JdbcUtils.class;//2.获取getConnenctionMethod m = clazz.getMethod("getConnection");//3.判断该方法上是否有 jdbcinfo注解 若有的话获取if(m.isAnnotationPresent(JdbcInfo.class)){//jdbcinfo注解 获取JdbcInfo info = m.getAnnotation(JdbcInfo.class);//4.获取注解四个属性String driverClass = info.driverClass();String url = info.url();String user = info.user();String password = info.password();//5.注册驱动Class.forName(driverClass);//6.获取连接return DriverManager.getConnection(url, user, password);}return null;}public static void main(String[] args) throws Exception {System.out.println(getConnection());//打印地址}
}

 

  • 1-5-3 运行的时候可以通过getConnection获取一个连接

    	public static void main(String[] args) throws Exception {System.out.println(getConnection());//打印地址}

     

  • 二、案例2-完成文件上传

技术分析:
文件上传

  1.         servlet3.0
  2.         commons-fileupload
  3.         框架
  • 2-1 servlet3.0

    3.0支持注解开发,没有web.xml这个文件了
内嵌了文件上传功能(2.5 无)
例如:

  •         创建servlet

            在类上面添加 @WebServlet(urlPatterns={ "/demo2", "/demo21" },loadOnStartup=2)

            urlPatterns  可以省略  @WebServlet({ "/demo2", "/demo21" })(一个servlet可以有多个路径)

@WebServlet(urlPatterns={ "/demo2", "/demo21" },loadOnStartup=2)
public class Demo2Servlet extends HttpServlet {@Overridepublic void init() throws ServletException {System.out.println("demo2  servlet初始化了");}private static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("demo2 servlet 执行了~~");}}
  •         创建listener

            在类上添加 @WebListener

@WebListener
public class MyServletContextLis implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {System.out.println("servletcontext 创建了.~");}@Overridepublic void contextDestroyed(ServletContextEvent sce) {// TODO Auto-generated method stub}}

 

  •         创建filter

            在类上添加 @WebFilter(urlPatterns="/*")

@WebFilter(urlPatterns="/demo2")
public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("filter 初始化了");}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {System.out.println("filter 接受到了请求");chain.doFilter(request, response);}@Overridepublic void destroy() {// TODO Auto-generated method stub}}

 

  • 2-2 文件上传

  • 2-2-1 浏览器端的要求

  1.     表单的提交方法必须是post
  2.     必须有一个文件上传组件  <input type="file" name=""/>
  3.     必须设置表单的enctype=multipart/form-data
  • 2-2-2 服务器端的要求

    servlet3.0中
1 需要在servlet中添加注解
       @MultipartConfig
2 接受普通上传组件 (除了文件上传组件):request.getParameter(name属性的值)
3 接受文件上传组件 request.getPart(name属性的值);

    获取的name的属性值
part.getName()
获取文件名:
part.getHeader("Content-Disposition"):获取头信息 然后截取

  •  2-2-3 案例简单实现

<body><form action="/day1701/upload1" method="post" enctype="multipart/form-data">用户名:<input name="username"><br/> 图片:<input type="file" name="f"><br/><input type="submit"></form>
</body>
@WebServlet("/upload1")
@MultipartConfig
public class Upload1Servlet extends HttpServlet {private static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//获取usernameString username = request.getParameter("username");System.out.println(username);//获取f 获取的内容为null/*String f = request.getParameter("f");System.out.println(f);*/Part part = request.getPart("f");//System.out.println(part);String name = part.getName();//获取name的值System.out.println(name);String dis = part.getHeader("Content-Disposition");//String dis = request.getHeader("Content-Disposition");System.out.println(dis);String s = dis.substring(dis.indexOf("filename=")+10,dis.length()-1);System.out.println(s);InputStream is = part.getInputStream();FileOutputStream os = new FileOutputStream("g:/"+s);IOUtils.copy(is, os);os.close();is.close();}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}}

 

  • 2-3 上传注意的问题

  • 2-3-1 名字重复 随机名称

    在数据库中提供两个字段,
一个字段用来存放文件的真实名称  1.jpg
另一个字段用来存放文件存放路径  g:/sdfasdf.jpg(随机名称)
随机名称:
uuid
时间戳

  • 2-3-2 文件安全

    重要的文件存放在 web-inf 或者 meta-inf 或者 服务器创建一个路径
不是很重  要的文件 项目下

  • 2-3-3 文件存放目录

    方式1:日期
方式2:用户
方式3:文件个数
方式4:随机目录
mkdirs

重新部署项目时,文件会消失----备份

  •  2-3-4 文件上传工具类

import java.util.UUID;public class UploadUtils {/*** 获取随机名称* @param realName 真实名称* @return uuid*/public static String getUUIDName(String realName){//realname  可能是  1.jpg   也可能是  1//获取后缀名int index = realName.lastIndexOf(".");if(index==-1){return UUID.randomUUID().toString().replace("-", "").toUpperCase();}else{return UUID.randomUUID().toString().replace("-", "").toUpperCase()+realName.substring(index);}//return null;}/*** 获取文件真实名称* @param name* @return*/public static String getRealName(String name){// c:/upload/1.jpg    1.jpg//获取最后一个"/"int index = name.lastIndexOf("\\");return name.substring(index+1);}/*** 获取文件目录* @param name 文件名称* @return 目录*/public static String getDir(String name){int i = name.hashCode();String hex = Integer.toHexString(i);int j=hex.length();for(int k=0;k<8-j;k++){hex="0"+hex;}//	System.out.println(hex);return "/"+hex.charAt(0)+"/"+hex.charAt(1);}public static void main(String[] args) {//String s="G:\\day17-基础加强\\resource\\1.jpg";String s="1.jgp";String realName = getRealName(s);//System.out.println(realName);String uuidName = getUUIDName(realName);//System.out.println(uuidName);String dir = getDir(realName);System.out.println(dir);}
}
  •  2-3-5 文件上传完善

<body><form action="/day1701/upload2" method="post" enctype="multipart/form-data">用户名:<input name="username"><br/> 文件:<input type="file" name="f"><br/><input type="submit"></form>
</body>
@WebServlet("/upload2")
@MultipartConfig
public class Upload2Servlet extends HttpServlet {private static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//0.设置编码request.setCharacterEncoding("utf-8");//1.获取普通的上传组件  usernameString username = request.getParameter("username");System.out.println(username);//2.获取文件上传组件Part part = request.getPart("f");//2.1获取文件的名称String sss = part.getHeader("content-disposition");String realName=sss.substring(sss.indexOf("filename=")+10, sss.length()-1);System.out.println("文件的名称:"+realName);//2.2 获取随机名称String uuidName = UploadUtils.getUUIDName(realName);System.out.println("文件随机名称:"+uuidName);//2.3 获取文件存放的目录String dir = UploadUtils.getDir(uuidName);String realPath = this.getServletContext().getRealPath("/upload"+dir);File file = new File(realPath);if(!file.exists()){file.mkdirs();}System.out.println("文件的目录:"+realPath);//3.对拷流InputStream is = part.getInputStream();FileOutputStream os = new FileOutputStream(new File(file,uuidName));IOUtils.copy(is, os);os.close();is.close();//4.删除临时文件part.delete();}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}}

 

  • 2-4 类加载器:(了解)

  • 2-4-1 类加载

    我们编写的.java文件,jvm会将变成.class文件.该文件要想运行,必须加载内存中,然后会生成一个对象.Class对象

  • 2-4-2 类加载器层次结构

    引导类加载器    rt.jar——核心   jdk/lib下   无法打印类加载器,结果为null(jvm启动时已经加载进去,不是class对象)
扩展类加载器    ext/*.jar    jdk/lib/ext下
应用类加载器    我们自己编写类

  • 2-4-5 全盘负责委托机制

    当一个类运行的时候,有可能有其他类,应用类加载器询问扩展类加载器:你加载过这些类吗?
扩展类加载器在向上问(引导类加载器):你加载过这些类吗?
引导类加载器:我查查,有一个是我负责,我加载.
扩展类加载器:接下来我来查,有几个是我负责,我加载,还有几个类我已经加载完成了,你可以直接使用
应用类加载器:收到了 剩下的我来

  • 三、案例3-统一编码

技术分析:
动态代理

  • 3-1 静态代理书写步骤

    1.要求被装饰者和装饰者实现同一个接口或者继承同一个类
2.在装饰者中要有被装饰者的引用
3.对需要加强的方法进行加强
4.对不需要加强的方法调用原来的方法

  • 3-2 动态代理

    在项目运行的时候才创建一个代理对象,对方法进行增强(控制)

  • 3-2-1 方式1-Proxy类

    jdk中Proxy类,前提:实现接口

  • 3-2-2 方式2-cglib

    spring中cglib,前提:继承类    

  • 3-2-3 动态的在内存中创建一个代理对象    

    Object Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 
参数说明:
ClassLoader:代理对象类加载器 一般我们使用的是被代理对象的类加载器
Class[]:代理对象需要实现接口 一般我们使用的是被代理对象所实现的所有接口
InvocationHandler:执行处理类(匿名内部类).在这里面对方法进行加强(要么是个接口,要么是个抽象类)
invocationHandler中只有一个方法
Object invoke(Object proxy, Method method, Object[] args) 
参数说明:
proxy:代理对象——newProxyInstance()的 返回值,自动传入
method:当前执行的方法
args:当前方法执行的时候所需要的参数
返回值:就是当前method对象执行的返回值

  • 3-3 步骤分析

    过滤器    
doFilter(Request request,Response response)    
将代理request传递过去
doFilter(Request requestPrxoy,Response response)

<body><form action="/day17/login" method="post">用户名:<input name="username"><br>备注:<input name="memo"><br><input type="submit"></form>
</body>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"><filter><filter-name>EncodingFilter</filter-name><filter-class>com.itheima.c_proxy.encoding.EncodingFilter</filter-class></filter><filter-mapping><filter-name>EncodingFilter</filter-name><url-pattern>/login</url-pattern></filter-mapping><servlet><description></description><display-name>LoginServlet</display-name><servlet-name>LoginServlet</servlet-name><servlet-class>com.itheima.c_proxy.encoding.LoginServlet</servlet-class></servlet><servlet-mapping><servlet-name>LoginServlet</servlet-name><url-pattern>/login</url-pattern></servlet-mapping>
</web-app>

 

public class EncodingFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)throws IOException, ServletException {//1.强转final HttpServletRequest request=(HttpServletRequest) req;HttpServletResponse response=(HttpServletResponse) resp;//创建代理对象HttpServletRequest requestProxy=(HttpServletRequest) Proxy.newProxyInstance(HttpServletRequest.class.getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if("getParameter".equals(method.getName())){//获取请求方式String m = request.getMethod();if("get".equalsIgnoreCase(m)){String s = (String) method.invoke(request, args);//相当于  request.getParameter(args);return new String(s.getBytes("iso8859-1"),"utf-8");}else if("post".equalsIgnoreCase(m)){request.setCharacterEncoding("utf-8");return method.invoke(request, args);}}//不需要加强的方法return method.invoke(request, args);}});//2.放行chain.doFilter(requestProxy, response);}@Overridepublic void destroy() {}}
public class LoginServlet extends HttpServlet {private static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String username = request.getParameter("username");String memo = request.getParameter("memo");System.out.println(username);System.out.println(memo);}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// TODO Auto-generated method stubdoGet(request, response);}}

 

  • 总结

  • 1 注解

    注释:给程序员看的
注解:给jvm看的

java中三个注解:
@Override:声明该方法是从父类上继承过来的
@SuppressWarnings:抑制警告 
@Deprecated:声明该方法不赞成使用            
自定义注解:
注解属性
类型:
基本类型
string
class
annotation
enum
以上类型的一维数组
若有属性,使用的时候必须有值                
元注解
@Retention:声明注解保留到那个阶段
SOURCE:
CLASS:
RUNTIME:
@Target:声明注解作用在那个部分
TYPE:
METHOD:
FILED:
注解的格式:
@interface 注解名{            
}        

  • 2 servlet3.0

    注解开发
@WebServlet(urlPatterns="/demo1")
@WebListener
@WebFilter(urlPatterns="/demo2")        
文件上传
浏览器端的要求:
表单的提交方式必须是post
表单必须有文件上传组件
表单的enctype属性值为 multipart/form-data        
服务器获取的时候
servlet3.0要求
添加一个@MultipartConfig
获取普通的组件  
request.getParameter(name属性的值)
获取文件上传组件
Part part=request.getPart("name属性的值")                    
//获取文件的名称
Stirng sss=part.getHeader("content-disposition")
//然后截取才能获取文件名称
sss.substring(sss.indexof("filename=")+10,sss.length-1);                
//获取文件流
part.getInputStream();                    
//删除临时文件
part.delete()                
上传时候需要注意的问题:
文件重名 随机名称
文件安全 重要的文件放在 web-inf meta-inf  服务器磁盘
目录分离
时间
用户
文件个数
随机目录

  • 3 动态代理(★)

    jdk中proxy
前提:实现接口        
Proxy.newProxyInstance(被代理对象.getClass().getClassLoader(),被代理对象.getClass().getInterfaces(),new InvocationHandler(){
invoke(代理对象,当前执行的方法,需要的参数){                        
}
});