javaweb-注解

1.注解的概述:

  • 从JDK5.0开始,Java增加了对元数据(描述数据的数据称之为元数据)的支持,也就是Annotation(注释)
  • Annotation其实就是代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过使用Annotation,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。
  • Annotation和类 接口同级

2.注解的格式:


   @interface 注解名{}

3.注解的作用:

  •         编译检查@override的那种
  •         替代配置文件
  •         定义注解(元注解:注解上的注解)
  •         分析代码(用到反射)

4. java中3个注解(理解)


        @Override:声明该方法是从分类上继承过来的,执行编译期的检查
        @SuppressWarnings:抑制警告 值有好多,只需要知道一个 all  抑制所有的警告
        @Deprecated:用来声明 该方法不赞成使用(要么过时要么有bug)                                                                                           编译器会给把代码中间写个横线用来提示不赞成使用

 5.自定义注解

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

        注解属性类型:
            基本类型
            String
            Class
            Annotation
            Enum:枚举
            以上类型对应的一维数组

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

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

6.元注解:

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

加上的注解默认是在源码阶段有,想要在runtime时候有加上 RUNTIME:

7.案例实现-模拟Junit测试

通过反射思想来获取字节码对象

然后通过字节码对象获取全部的方法

然后再获取带有注解的方法

最后m.invoke就可以执行了

package com.itheima.a_annotation;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

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

8.案例实现获得连接:(替代配置文件)


通过注解来获取配置文件

    1.自定义一个注解JDBCInfo
        添加元注解:
            在程序运行的时候使用  @Retention
            只能作用在方法上      @Target
        添加注解属性
            String driverClass() default "com.mysql.jdbc.Driver";
            String url();
            String username() default "root";
            String password();
    2.在jdbcutils工具类中提供一个getConnection,在方法上面添加一个注解 @JDBCInfo(...) 
        getConnection方法需要进行的操作:获取注解上的四个属性值
            获取字节码文件
            获取该方法上的注解
            获取注解的值
    3.运行的时候可以通过getConnection获取一个连接

代码实现:

step1;定义一个info注解

package com.javaweb.annotationPlus;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@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";

}

step2定义一个类叫做jdbcutils

package com.itheima.a_annotation.plus;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;

public class JdbcUtils {
	@JdbcInfo(url = "jdbc:mysql://localhost:3306/day16",password="1234")
	public static Connection getConnection() throws Exception{
		//1.获取字节码文件
		Class clazz=JdbcUtils.class;★★★
		
		//2.获取getConnenction
		Method m = clazz.getMethod("getConnection");
		
		//3.判断该方法上是否有 jdbcinfo注解 若有的话获取
		if(m.isAnnotationPresent(JdbcInfo.class)){
			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());★★
	}
}

结果:

9.文件上传

1.文件上传定义:(将文件发送到服务器,通过请求信息发送过去,通过流来实现)

2.实现方法

       ①servlet3.0
       ② commons-fileupload
       ③ 框架

3.servlet3.0介绍:


    3.0支持注解开发,没有web.xml这个文件了
    内嵌了文件上传功能

    例如:
      3.1  创建servlet(可以匹配多个路径)
            在类上面添加 @WebServlet(urlPatterns={ "/demo2", "/demo21" },loadOnStartup=2)

@WebServlet(urlPatterns="/demo1")
public class Demo1Servlet extends HttpServlet {
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		System.out.println("demo1servlet执行了");
	}

}


       3.2 创建listener(没路径需求不用加路径)
            在类上添加 @WebListener

@WebListener
public class MyServletContextLis implements ServletContextListener {

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		System.out.println("servletcontext 创建了.~");
	}
}


       3.3 创建filter(这里拦截所有用/*)
            在类上添加 @WebFilter(urlPatterns="/*")

@WebFilter(urlPatterns="/demo2")
public class MyFilter implements Filter {

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		System.out.println("filter 初始化了");
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {

		System.out.println("filter 接受到了请求");
		
		chain.doFilter(request, response);
	}
}

4.文件上传

  浏览器端的要求:
        表单的提交方法必须是post
        必须有一个文件上传组件  <input type="file" name=""/>
        必须设置表单的enctype=multipart/form-data

    服务器端的要求:
        servlet3.0中
            需要在servlet中添加注解
                @MultipartConfig
            接受普通上传组件 (除了文件上传组件):request.getParameter(name属性的值)
            接受文件上传组件 request.getPart(name属性的值);
                getName():获取的name的属性值
            获取文件名:
                 part.getHeader("Content-Disposition"):获取头信息 然后截取

代码实现:

form.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>Insert title here</title>
</head>
<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>
</html>

servlet

package com.itheima.web.servlet;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

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;

import org.apache.commons.io.IOUtils;

@WebServlet("/upload1")
@MultipartConfig
public class Upload1Servlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//获取username
		String 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);
	}

}

上传注意的问题:
    名字重复 随机名称
        在数据库中提供两个字段,      一个字段用来存放文件的真实名称  1.jpg
            另一个字段用来存放文件存放路径  g:/sdfasdf.jpg
        随机名称:
            uuid
            时间戳
    文件安全
        重要的文件存放在 web-inf 或者 meta-inf 或者 服务器创建一个路径
        不是很重要的文件 项目下
        
    文件存放目录
        方式1:日期
        方式2:用户
        方式3:文件个数
        方式4:随机目录
            mkdirs

代码实现2加上工具类Plus

step1:新建一个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>Insert title here</title>
</head>
<body>
	<form action="/day1101/upload2" method="post" enctype="multipart/form-data">
		用户名:<input name="username"><br/> 
		文件:<input type="file" name="f"><br/>
		<input type="submit">
	</form>
</body>
</html>

step2:新建一个servlet

package com.javaweb.servlet;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

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;

import org.apache.commons.io.IOUtils;

import com.javaweb.utils.UploadUtils;

@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.获取普通的上传组件  username
		String 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);
	}

}

step3:UpLoadUtils实现(理解)

package com.javaweb.utils;

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="0";
		String s1="1.jpg";
		//System.out.println(getUUIDName(s));
		//System.out.println(getUUIDName(s1));
		//System.out.println(getRealName(s));
		//System.out.println(getRealName(s1));
		System.out.println(getDir(s));
		System.out.println(getDir(s1));
		//getDir(s);
		//getDir(s1);
	}
}

结果演示:

10.类加载器

类加载器:(了解)
    类加载:
        我们编写的.java文件,jvm会将变成.class文件.该文件要想运行,必须加载内存中,然后会生成一个对象.Class对象
    类加载器层次结构
        引导类加载器    rt.jar
        扩展类加载器    ext/*.jar
        应用类加载器    我们自己编写类
    全盘负责委托机制:
        当一个类运行的时候,有可能有其他类,应用类加载器询问扩展类加载器:你加载过这些类吗?
        扩展类加载器在向上问(引导类加载器):你加载过这些类吗?
        引导类加载器:我查查,有一个是我负责,我加载.
        扩展类加载器:接下来我来查,有几个是我负责,我加载,还有几个类我已经加载完成了,你可以直接使用
        应用类加载器:收到了 剩下的我来

11.案例实现统一编码(动态代理实现)

静态代理书写步骤:
    1.要求被装饰者和装饰者实现同一个接口或者继承同一个类
    2.在装饰者中要有被装饰者的引用
    3.对需要加强的方法进行加强
    4.对不需要加强的方法调用原来的方法
////////////////////////////
动态代理:
    在项目运行的时候才创建一个代理对象,对方法进行增强(控制)
    方式1:
        jdk中Proxy类,前提:实现接口
    方式2:
        spring中cglib,前提:继承类
        
    动态的在内存中创建一个代理对象    
        Object Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 
            参数说明:
                ClassLoader:代理对象类加载器 一般我们使用的是被代理对象的类加载器
                Class[]:代理对象需要实现接口 一般我们使用的是被搭理对象所实现的所有接口
                InvocationHandler:执行处理类.在这里面对方法进行加强

            invocationHandler中只有一个方法
                Object invoke(Object proxy, Method method, Object[] args) 
                    参数说明:
                        proxy:代理对象
                        method:当前执行的方法
                        args:当前方法执行的时候所需要的参数
                        返回值:就是当前method对象执行的返回值

  

QQ飞车代码实现

step1:新建一个接口Car

package com.javaweb.proxy;

public interface Car {
	void run();
	void stop();
}

step2:新建一个QQ类实现Car

package com.javaweb.proxy;

public class QQ implements Car{
	@Override
	public void run() {
		System.out.println("qq在跑");
	}

	@Override
	public void stop() {
		System.out.println("qq刹车");
	}


}

step3:测试类(以前用到的是静态代理装饰者模式,这次是动态代理,只需要一个方法)

package com.javaweb.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class TT {
public static void main(String[] args) {
	QQ qq=new QQ();
	
	//创建代理对象★★★
	Car qqProxy=(Car) Proxy.newProxyInstance(QQ.class.getClassLoader(), new Class[]{Car.class}, new InvocationHandler() {
		@Override
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			//System.out.println("哈哈哈哈");
			//System.out.println(method.getName());
			//obj 就是代理对象★★★
			//Object obj=method.invoke(qq, args);
			//return obj;
			
			//对所有方法进行加强★★
			/*System.out.println("加上电池");
			Object obj = method.invoke(qq, args);
			System.out.println("5秒破百");
			
			return obj;*/
			
			
			//只对run方法进行加强★★★
			if("run".equals(method.getName())){
				System.out.println("加上电池");
				Object obj = method.invoke(qq, args);
				System.out.println("5秒破百");
				return obj;
			}
			return method.invoke(qq, args);★★
		}
	});
	
	qqProxy.run();
	//qqProxy.stop();
}
}

 过滤器最后的放行方法进行动态代理 
        doFilter(Request request,Response response)
    
        将代理request传递过去
        doFilter(Request requestPrxoy,Response response)
    对requestPrxoy加强

放行的时候servllet获取数据的时候就直接是中文

统一编码代码实现

step1:新建一个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>Insert title here</title>
</head>
<body>
	<form action="/day11/Login" method="post">★★★
		用户名:<input name="username"><br>
		备注:<input name="memo"><br>
		<input type="submit">
	</form>
</body>
</html>

step2:新建一个servlet(使用动态代理实现的request.getParameter)解决乱码问题

package com.javaweb.proxy.encoding;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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 stub
		doGet(request, response);
	}

}

step3:新建一个Filter

package com.javaweb.proxy.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.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class EncodingFilter implements Filter {

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {

	}

	@Override
	public 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() {
			
			@Override★★★
			public 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);
		
	}

	@Override
	public void destroy() {

	}

}

step4:配置Filter

 <filter>
      <filter-name>EncodingFilter</filter-name>
      <filter-class>com.javaweb.proxy.encoding.EncodingFilter</filter-class>
  </filter>
  <filter-mapping>
      <filter-name>EncodingFilter</filter-name>
      <url-pattern>/Login</url-pattern>
  </filter-mapping>

结果演示:

打印输出:

总结:

熟悉注解

UpLoadUtils工具类的实现

动态代理实现统一编码

猜你喜欢

转载自blog.csdn.net/JQ210245253/article/details/89444645