一,元注解使用
@Target
定义
@Target(value = {
ElementType.TYPE ,
ElementType.FIELD ,
ElementType.METHOD ,
ElementType.PARAMETER ,
ElementType.LOCAL_VARIABLE }
)
public @interface MyAnnotation01 {
String value() default "hello annotation";
}
使用
@MyAnnotation01
public class Demo01 {
@MyAnnotation01
private int num = 1;
@MyAnnotation01
public static void main(@MyAnnotation01 String[] args) {
@MyAnnotation01
int num = 1;
}
}
@Retention
定义
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation01 {
String value() default "hello annotation";
}
一般情况下,注解存活策略是RUNTIME,
注解要起作用,必须结合反射使用,而反射是在程序运行时(RUNTIME)执行!
二,自定义注解@MyTest
开发步骤
自定义注解@MyTest
在测试类Test01上使用@MyTest
让@MyTest注解生效
获取到Test01类对应的Class对象
获取Test01类中的所有方法
判断方法上是否有@MyTest注解
如果有,就将该方法执行
如果没有,就不处理
@MyTest注解:@MyTest的存活策略必须是RUNTIME
package t1.example.anno;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
}
Test01测试类
package t1.example.test;
import org.junit.Test;
import t1.example.anno.MyTest;
public class Test01 {
@Test
public void test01(){
System.out.println("test01");
}
@MyTest
public void test02(){
System.out.println("test02");
}
@MyTest
public void test03(){
System.out.println("test03");
}
public void test04(){
System.out.println("test04");
}
}
demo类!!!
package t1.example.demo;
import org.junit.Test;
import t1.example.anno.MyTest;
import t1.example.test.Test01;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* 让@MyTest生效起作用
*/
public class Demo02 {
public static void main(String[] args) {
//使用反射,扫描Test01类里面有哪些方法有@MyTest注解
//如果有@MyTest注解,就将起执行
//如果没有@MyTest注解,不做任何处理
Class<Test01> clazz = Test01.class;
Method[] methods = clazz.getMethods();
Arrays.stream(methods).forEach(method -> {
//method就是单个方法对象
boolean present = method.isAnnotationPresent(MyTest.class);
if (present) {
//方法上有@MyTest注解,执行方法
try {
method.invoke(clazz.newInstance());
} catch (Exception e) {
e.printStackTrace();
}
} else {
//方法上没有@MyTest注解
}
});
}
}
三,自定义注解@JDBCInfo
–使用注解@JDBCInfo替代jdbc.properties配置文件
–开发步骤
- 自定义注解@JDBCInfo
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface JDBCinfo {
String driverClass() default "com.mysql.jdbc.Driver";
String jdbcUrl() default "jdbc:mysql://localhost:3306/account";
String username() default "root";
String password() default "19951023sun";
}
- 在JDBCUtils工具类上使用@JDBCInfo
- 在JDBCUtils工具类中静态代码块中,获取@JDBCInfo注解上的属性,并给JDBCUtils工具类中成员变量赋值
@JDBCinfo
public class JDBCUtils {
private static final String DRIVERCLASS;
private static final String JDBCURL;
private static final String USER;
private static final String PASSWORD;
static {
Class<JDBCUtils> clazz = JDBCUtils.class;
boolean present = clazz.isAnnotationPresent(JDBCinfo.class);
if(present){
JDBCinfo jdbCinfo = clazz.getAnnotation(JDBCinfo.class);
DRIVERCLASS = jdbCinfo.driverClass();
JDBCURL = jdbCinfo.jdbcUrl();
USER = jdbCinfo.username();
PASSWORD = jdbCinfo.password();
}else {
Properties properties = new Properties();
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("db.properties");
try {
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}
DRIVERCLASS = properties.getProperty("driverClass");
JDBCURL = properties.getProperty("jdbcUrl");
USER = properties.getProperty("username");
PASSWORD = properties.getProperty("password");
}
}
public static void loadDriver() throws Exception {
Class.forName(DRIVERCLASS);
}
public static Connection getConnection() throws Exception {
loadDriver();
return DriverManager.getConnection(JDBCURL,USER,PASSWORD);
}
public static void release(Connection connection, Statement statement, ResultSet resultSet){
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
connection = null;//为了Connection对象既是被jvm回收
}
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
statement = null;
}
if(resultSet!=null ){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
resultSet=null;
}
}
public static void release(Connection connection, Statement statement){
release(connection,statement,null);
}
}
四,反射、注解、设计模式初级版
开发步骤
自定义注解@SystemLog
- className
- methodName
定义一个UserDao接口,且在该接口使用注解@SystemLog
编写装饰者设计模式
@SystemLog
@Retention(RetentionPolicy.RUNTIME)
public @interface SystemLog {
String className();
String methodName();
}
UserDao
public interface UserDao {
void addUser() throws Exception;
@SystemLog(className = "t1.example.dao.UserDao",methodName = "deleteUser")
void deleteUser() throws Exception;
void updateUser() throws Exception;
}
UserDaoImpl
public class UserDaoImpl implements UserDao {
@Override
public void addUser() throws Exception {
System.out.println("UserDaoImpl addUser");
}
@Override
public void deleteUser() throws Exception {
System.out.println("UserDaoImpl deleteUser");
}
@Override
public void updateUser() throws Exception {
System.out.println("UserDaoImpl updateUser");
}
}
UserDaoWrapper
public class UserDaoWrapper implements UserDao {
private UserDao userDao;
public UserDaoWrapper(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void addUser() throws Exception {
userDao.addUser();
printLog("addUser");
}
@Override
public void deleteUser() throws Exception {
userDao.deleteUser();
printLog("deleteUser");
}
@Override
public void updateUser() throws Exception {
userDao.updateUser();
printLog("updateUser");
}
/**
* 日志记录
* @param runMethodName
*/
public void printLog(String runMethodName) throws Exception {
//需要判断接口对应方法上是否又@SystemLog注解
//1,获取UserDao接口实现子类的Class对象
Class<? extends UserDao> sonClazz = userDao.getClass();
//2,获取子类对应的接口
Class<?>[] clazzInterfaces = sonClazz.getInterfaces();
Class<?> clazzInterface = clazzInterfaces[0];
//3,获取接口中方法,
Method method = clazzInterface.getMethod(runMethodName);
if(method!=null){
//找到被@SystemLog标记的方法,并打印日志
boolean present = method.isAnnotationPresent(SystemLog.class);
if(present){
//有标注,打印日志
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
Date currentDate = new Date();
String currentTimeStr = simpleDateFormat.format(currentDate);
//通过注解属性拿到类以及方法
SystemLog systemLog = method.getAnnotation(SystemLog.class);
String className = systemLog.className();
String methodName = systemLog.methodName();
System.out.println(currentTimeStr+"---"+className+"类中---"+methodName+"()方法 ---运行了");
}else {
//没有@SystemLog注解,不做任何处理
}
}
}
}
存在的问题:
装饰类中的每个方法都需要调用printLog方法,由装饰着设计模式的缺点决定
五,反射、注解、设计模式优化版
开发步骤;
自定义注解@SystemLog
- className
- methodName
@Retention(RetentionPolicy.RUNTIME)
public @interface SystemLog {
String className();
String methodName();
}
- 定义一个UserDao接口,且在该接口使用注解@SystemLog
public interface UserDao {
void addUser() throws Exception;
@SystemLog(className = "t1.example.dao.UserDao",methodName = "deleteUser")
void deleteUser() throws Exception;
void updateUser() throws Exception;
}
- 动态代理
- `/**
- 反射,注解,设计模式综合案例之动态代理
*/
public class Demo05 {
public static void main(String[] args) throws Exception {
UserDao userDao = new UserDaoImpl();
UserDao userDaoProxy=(UserDao) Proxy.newProxyInstance(
userDao.getClass().getClassLoader(),
userDao.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//获取到接口中方法对象 , 比如 : UserDao接口中addUser方法
//之前
//先获取实现子类的Class对象
//再获取到接口的Class对象
//再获取到接口中的方法对象
//现在
//再获取到接口的Class对象 -- userDao.getClass().getInterfaces(),
//再获取到接口中的方法对象 -- Method method
//method : 就是接口中的方法对象
Object returnValue = null;
if (method != null) {
boolean present = method.isAnnotationPresent(SystemLog.class);
if (present) {
returnValue = method.invoke(userDao, args);
//有标注,打印日志
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
Date currentDate = new Date();
String currentTimeStr = simpleDateFormat.format(currentDate);
//通过注解属性拿到类以及方法
SystemLog systemLog = method.getAnnotation(SystemLog.class);
String className = systemLog.className();
String methodName = systemLog.methodName();
System.out.println(currentTimeStr + "---" + className + "类中---" + methodName + "()方法 ---运行了");
} else {
returnValue = method.invoke(userDao, args);
}
}
return returnValue;
}
}
);
userDaoProxy.addUser();
userDaoProxy.deleteUser();
}
}
`
六,request与response对象介绍
概念:当浏览器发起请求后,服务器会创建一个请求对象、一个响应对象,通过service方法传入给Serlvet
作用:
- request对象处理请求信息(请求行、请求头、请求正文)
- response对象处理响应信息(响应行、响应头、响应正文)
ServletRequest和HttpServletRequest的关系、ServletResponse和HttpServletResponse的关系?
-
ServletRequest是HttpServletRequest的父接口,
-
ServletResponse是HttpServletResponse的父接口,
-
HttpServletRequest针对Http协议、HttpServletResponse针对Http协议
七,response对象操作响应行、响应头
操作响应行
- setStatus:操作正常响应状态码,比如:200、302
- sendError:操作错误响应状态码,比如: 404
操作响应头 - setHeader:直接覆盖响应头原有值
- addHeader:在响应头原有值的后面追加
@WebServlet(name="Demo01Servlet",urlPatterns = "demo01")
public class Demo01Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//response对象操作响应行(响应状态码)
//操作正常状态码 : 200 , 302
//200:告诉浏览器,响应成功。
//302:重定向。
//304:页面没有发生。
resp.setStatus(200);
//操作错误状态码
// resp.sendError(404);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
/**
* response对象操作响应行,响应头
*/
@WebServlet(name="Demo02Servlet",urlPatterns = "demo02")
public class Demo02Servlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//操作响应头
//setHeader():覆盖原有的响应头的值
//addHeader():在原有的响应头的值后面追加 (Cookie)
//服务器告诉浏览器,给的响应正文的类型是text/html,告诉你应该以utf-8进行解码
resp.setHeader("Content-Type","text/html;charset=utf-8");
System.out.println("Demo02Servlet doPost");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
}
八,response操作重定向
重定向的流程
- 当浏览器访问一个资源Demo03Servlet,访问名称为“/demo03”
- Demo03Servlet进行重定向
- 操作响应状态码302
- 操作响应头Location,服务器告诉浏览器,重定向的资源的访问路径
- 浏览器进行一个新的请求,完成重定向
@WebServlet(name = "Demo03Servlet" ,urlPatterns = "/demo03")
public class Demo03Servlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//重定向:从一个资源跳转到另外一个资源
//方法一
// resp.setStatus(302);
// resp.setHeader("Location","demo04");
//方法二
resp.sendRedirect("demo04");
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
重定向除了可以从Servlet重定向到Servlet外,也可以转向其他类型资源
九,response操作定时跳转
一个资源定时一段时间之后,跳转到另外一个资源
代码如下,操作refresh响应头
resp.setHeader("refresh","5;url=demo07");