Annotation
注解
从JDK5开始,Java增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。
语法:
@Target
(
ElementType
.
xxxx
)
@Retention
(
RetentionPolicy
.
xxxx
)
public @interface
注解名
{
}
Target:对应的是当前的注解能够定义在哪个位置
上
ElementType.Type -- 类
ElementType.Field --字段
@Target(ElementType.xxxx)
@Retention(RetentionPolicy.xxxx)
public @interface 注解名 {
}
ElementType.Method --方法
Retention:在什么场景下能够起作用。
RetentionPolicy.CLASS - 定义类
RetentionPolicy.RUNTIME --运行时
定义两个Annotation:
package com.csi.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
}
package com.csi.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
String value() default "";
}
解析Annotation
package com.csi.listener;
import com.csi.annotation.Controller;
import com.csi.annotation.RequestMapping;
import com.csi.utils.ClassScanner;
import javax.servlet.ServletContextEvent;
import javax.servlet.servletcontextlistener;
import java.lang.reflect.Method;
import java.util.List;
public class ClassLoaderContextListener implements servletcontextlistener {
@Override
public void contextinitialized(ServletContextEvent sce) {
initClassLoader() ;
}
private void initClassLoader() {
//根据包找到包下面所有的类
List<Class<?>> classList = ClassScanner.getClasssFromPackage("com.csi.controller");
for (Class clazz : classList) {
//如果当前类上存在Controller,就要获取方法
if(clazz.isAnnotationPresent(Controller.class)) {
Method[] methods = clazz.getmethods();
//遍历当前包含了Controller注解的所有方法
for (Method method : methods) {
//判断方法上是否添加了RequestMapping注解
if(method.isAnnotationPresent(RequestMapping.class)) {
//获取到包含了RequestMapping注解的value值
String urlPath = method.getAnnotation(RequestMapping.class).value();
//将值作为键,将方法作为值,存储在map集合中
WebApplicationContext.methodMap.put(urlPath,method) ;
}
}
}
}
}
}
package com.csi.listener;
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
public class WebApplicationContext {
public static ConcurrentHashMap<String, Method> methodMap = new ConcurrentHashMap<>() ;
}
解析用户的请求路径
package com.csi.servlet;
import com.csi.listener.WebApplicationContext;
import javax.servlet.servletexception;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class dispatcherServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws servletexception, IOException {
//步骤1:获取到用户的请求URL
String urlPath = req.getServletPath() ;
Method method = WebApplicationContext.methodMap.get(urlPath);
if(method != null) {
//步骤2:调用对应的Method方法
//2-1:如何找到要对应的类
Object instance = null;
try {
instance = method.getDeclaringClass().newInstance();
} catch (InstantiationException e) {
e.printstacktrace();
} catch (illegalaccessexception e) {
e.printstacktrace();
}
//2-2:如何传输参数,request,response
try {
method.invoke(instance,req,resp) ;
} catch (illegalaccessexception e) {
e.printstacktrace();
} catch (InvocationTargetException e) {
e.printstacktrace();
}
}else{
resp.sendRedirect("failure.jsp");
}
}
}
package com.csi.utils;
import java.io.File;
import java.io.FileFilter;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
/**
* 找到某个包下的所有的以.class结尾的java文件
*/
public class ClassScanner {
/**
* 获得包下面的所有的class
* @param
* @return List包含所有class的实例
*/
public static List<Class<?>> getClasssFromPackage(String packageName) {
List<Class<?>> clazzs = new ArrayList<>();
// 是否循环搜索子包
boolean recursive = true;
// 包名对应的路径名称
String packageDirName = packageName.replace('.', '/');
Enumeration<URL> dirs;
try {
//从当前正在运行的线程中,加载类加载器,通过给定的包名,找到所有该包下的类
dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
while (dirs.hasMoreElements()) {
URL url = dirs.nextElement();
String protocol = url.getProtocol();
if ("file".equals(protocol)) {
String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
findClassInPackageByFile(packageName, filePath, recursive, clazzs);
}
}
} catch (Exception e) {
e.printstacktrace();
}
return clazzs;
}
/**
* 在package对应的路径下找到所有的class
*/
public static void findClassInPackageByFile(String packageName, String filePath, final boolean recursive,
List<Class<?>> clazzs) {
File dir = new File(filePath);
if (!dir.exists() || !dir.isDirectory()) {
return;
}
// 在给定的目录下找到所有的文件,并且进行条件过滤
File[] dirFiles = dir.listFiles(new FileFilter() {
public boolean accept(File file) {
boolean acceptDir = recursive && file.isDirectory();// 接受dir目录
boolean acceptClass = file.getName().endsWith("class");// 接受class文件
return acceptDir || acceptClass;
}
});
for (File file : dirFiles) {
if (file.isDirectory()) {
findClassInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, clazzs);
} else {
String className = file.getName().substring(0, file.getName().length() - 6);
try {
clazzs.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + "." + className));
} catch (Exception e) {
e.printstacktrace();
}
}
}
}
}
框架的使用
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<listener>
<listener-class>com.csi.listener.ClassLoaderContextListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>com.csi.servlet.dispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
CodeServlet
package com.csi.utils;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.servletexception;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CodeServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
public static final int WIDTH = 120;//生成图片的宽度
public static final int HEIGHT = 30;//生成图片的高度
public static final int WORDS_NUMBER = 4;//验证码中字符的个数
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws servletexception, IOException {
// Todo Auto-generated method stub
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws servletexception, IOException {
// Todo Auto-generated method stub
String createTypeFlag = req.getParameter("createTypeFlag");//接收客户端传递的createTypeFlag标识
//在内存中创建一张图片
BufferedImage bi = new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_3BYTE_BGR);
//得到图片
Graphics g = bi.getGraphics();
//设置图片的背景色
setBackGround(g);
//设置图片的边框
setBorder(g);
//在图片上画干扰线
drawRandomLine(g);
//在图片上放上随机字符
String randomString = this.drawRandomNum((Graphics2D)g, createTypeFlag);
//将随机数存在session中
req.getSession().setAttribute("scode", randomString);
System.out.println(randomString);
//设置响应头通知浏览器以图片的形式打开
resp.setContentType("image/jpeg");
//设置响应头控制浏览器不要缓存
resp.setDateHeader("expries", -1);
resp.setHeader("Cache-Control", "no-cache");
resp.setHeader("Pragma", "no-cache");
//将图片传给浏览器
ImageIO.write(bi, "jpg", resp.getoutputStream());
}
//设置图片背景色
//@param g
private void setBackGround(Graphics g) {
//设置颜色
g.setColor(Color.WHITE);
//填充区域
g.fillRect(0, 0, WIDTH, HEIGHT);
}
/*
* 设置图片的边框
* @param g
* */
private void setBorder(Graphics g) {
//设置边框颜色
g.setColor(Color.RED);
//边框区域
g.drawRect(2, 2, WIDTH - 2, HEIGHT -2);
}
/*
* 在图片上画随机线条
* @param g
* */
private void drawRandomLine(Graphics g) {
//设置颜色
g.setColor(Color.GREEN);
//设置线条个数并画线
for ( int i = 0 ; i < 30 ; i++ ) {
int x1 = new Random().nextInt(WIDTH);
int y1 = new Random().nextInt(HEIGHT);
int x2 = new Random().nextInt(WIDTH);
int y2 = new Random().nextInt(HEIGHT);
g.drawLine(x1, y1, x2, y2);
}
}
/*
* 在图片上画随机字符
* @param g
* @param createTypeFlag
* @return String
* */
private String drawRandomNum(Graphics g,String createTypeFlag) {
//设置颜色
g.setColor(Color.RED);
g.setFont(new Font("微软雅黑",Font.BOLD,20));
//数字字母的组合
String baseNumLetter = "123456789ABCDEFGHJKLMNPQRSTUVWXYZ";
String baseNum = "123456789";
String baseLetter = "ABCDEFGHJKLMNPQRSTUVWXYZ";
if ( createTypeFlag != null && createTypeFlag.length() > 0 ) {
if( createTypeFlag.equals("nl") ) {
//截取数字和字母的组合
return createrandomChar((Graphics2D) g,baseNumLetter);
} else if ( createTypeFlag.equals("n") ) {
//截取数字的组合
return createrandomChar((Graphics2D) g,baseNum);
} else if ( createTypeFlag.equals("l") ) {
//截取字母的组合
return createrandomChar((Graphics2D) g,baseLetter);
}
} else {
//截取数字和字母的组合
return createrandomChar((Graphics2D) g,baseNumLetter);
}
return "";
}
/*
* 创建随机字符
* @param g
* @param baseChar
* @return String
* */
private String createrandomChar(Graphics2D g , String baseChar) {
StringBuffer b = new StringBuffer();
int x = 5;
String ch = "";
for ( int i = 0 ; i < WORDS_NUMBER ; i++ ) {
//设置字体的旋转角度
int degree = new Random().nextInt() % 30;
ch = baseChar.charat(new Random().nextInt(baseChar.length())) + "";
b.append(ch);
//正向角度
g.rotate(degree * Math.PI / 180 , x,20);
g.drawString(ch, x, 20);
//反向角度
g.rotate(-degree * Math.PI / 180 , x,20);
x+=30;
}
return b.toString();
}
}