Java学习第54天--元注解使用,自定义注解,反射注解设计模式,request,response

一,元注解使用
@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");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值