- 从JDK5.0开始,Java增加了对元数据(描述数据的数据称之为元数据)的支持,也就是Annotation(注释)
- Annotation其实就是代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过使用Annotation,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。
- Annotation和类 接口同级
@interface 注解名{}
- 编译检查@override的那种
- 替代配置文件
- 定义注解(元注解:注解上的注解)
- 分析代码(用到反射)
@Override:声明该方法是从分类上继承过来的,执行编译期的检查
@SuppressWarnings:抑制警告 值有好多,只需要知道一个 all 抑制所有的警告
@Deprecated:用来声明 该方法不赞成使用(要么过时要么有bug) 编译器会给把代码中间写个横线用来提示不赞成使用
注解属性:
注解本质就是一个接口,接口中可以有常量和抽象方法
抽象方法在注解中就称之为注解属性注解属性类型:
基本类型
String
Class
Annotation
Enum:枚举
以上类型对应的一维数组注意:
一旦注解有属性了,使用注解的时候必须赋值,(除非这个注解属性有默认值)赋值的格式:
@注解名(属性名=属性值)
若注解类型为数组,且只有一个值的时候,可以有两种写法
方式1:
属性名 = { 值 }
方式2:
属性名=属性值
若属性名为value的时候,且只需要为这个value属性赋值的时候,value可以省略
定义在注解上的注解
@Retention 规定注解保留到什么阶段 值为RetentionPolicy的三个枚举值
SOURCE:只在代码中保留,在字节码文件中就删除了
CLASS:在代码和字节码文件中保留
RUNTIME:所有阶段都保留
@Target 规定注解作用在什么上面 值为ElementType的枚举值
TYPE:作用在类 接口 等上面
METHOD:作用方法上面
FIELD:作用字段上面加上的注解默认是在源码阶段有,想要在runtime时候有加上 RUNTIME:
通过反射思想来获取字节码对象
然后通过字节码对象获取全部的方法
然后再获取带有注解的方法
最后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());//★★★
}
}
}
}
通过注解来获取配置文件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());★★ } }
结果:
①servlet3.0
② commons-fileupload
③ 框架
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);
}
}
浏览器端的要求:
表单的提交方法必须是post
必须有一个文件上传组件
必须设置表单的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"%>
Insert title here
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
step1:新建一个jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
Insert title here
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);
}
}
结果演示:
类加载器:(了解)
类加载:
我们编写的.java文件,jvm会将变成.class文件.该文件要想运行,必须加载内存中,然后会生成一个对象.Class对象
类加载器层次结构
引导类加载器 rt.jar
扩展类加载器 ext/*.jar
应用类加载器 我们自己编写类
全盘负责委托机制:
当一个类运行的时候,有可能有其他类,应用类加载器询问扩展类加载器:你加载过这些类吗?
扩展类加载器在向上问(引导类加载器):你加载过这些类吗?
引导类加载器:我查查,有一个是我负责,我加载.
扩展类加载器:接下来我来查,有几个是我负责,我加载,还有几个类我已经加载完成了,你可以直接使用
应用类加载器:收到了 剩下的我来
静态代理书写步骤:
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"%>
Insert title here
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
EncodingFilter
com.javaweb.proxy.encoding.EncodingFilter
EncodingFilter
/Login
结果演示:
打印输出:
熟悉注解
UpLoadUtils工具类的实现
动态代理实现统一编码