`
sdh88hf
  • 浏览: 69582 次
  • 性别: Icon_minigender_1
  • 来自: 绍兴
社区版块
存档分类
最新评论

Web开发学习13聊聊java反射

阅读更多
很喜欢一本叫《走出软件作坊》的书,其中有一句话让我较为深刻,“架构师,客户和程序员之间走钢丝的人”,一个优秀的程序员过单行线都会左右都看看,更何况一个架构师肯定是需要非常谨慎的。那怎么样才能做到谨慎呢?在我看来对于架构师的谨慎其实就是一句话:不要让程序员写原本不应该是他写的代码,这句话说的好像有点抽象,但其实很好理解,就是尽可能让程序员的代码变的少,这样不但开发起来效率快,而且review代码以及排查bug都是很方便的,那怎么样才能让程序员写的代码变少呢?今天我想借java的反射来举几个例子,通过反射封装让编码变的更简单,当然这肯定不是唯一的办法。

1.excel文件导出
这个封装是在我工作两年的时候自己想的,当时真的被逼的没办法,十几个模块都需要添加excel导出功能,当做出来以后确实被自己感动了,同时感觉封装的重要性。首先要创建一个注解类

/**
 * 
 * @author sdh 2012-7-26
 */
@Target(value={java.lang.annotation.ElementType.METHOD,java.lang.annotation.ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Export{

	/**
	 * @return 表头名称
	 */
	String header() default " ";

	/**
	 * @return 排序
	 */
	int sort();
	
	/**
	 * 设定列宽
	 * @return
	 */
	int columnWidth() default 100;
	
	/**
	 * 状态转换
	 * @return
	 */
	String stateStr() default "";
	
}

header标志列头名称,sort标志排第几列,columnWidth标志列宽,stateStr是状态转换,当数据库是int类型转成中文时用,然后在需要导出的实体类字段中按需求添加注解配置
public class Coupon implements IBasicBean {

	private static final long serialVersionUID = -8233437005461628357L;
	private Long id;
	@Export(header="业务类型",sort=0,stateStr="1:印刷品,2:DM,3:视频")
	private Integer businessType;
	@Export(header="产品编号",sort=1)
	private Integer productId;
	@Export(header="优惠券编号",sort=2)
	private String couponNum;
	@Export(header="优惠券名称",sort=3)
	private String couponName;
	@Export(header="优惠券价格",sort=4)
	private Float couponPrice;
}

看封装类投代码
public class ExcelExportUtils<T> {

	public ExcelExportUtils() {

	}

用泛型类来配合反射是常用的手段,只需在调用时传递操作类型即可在封装类中反射出来了,调用方传递操作类型和该操作类型的数据集,封装类通过反射获取字段上的注解后去数据集中获取该字段的值即可完成导出逻辑,篇幅关系这里不做详细代码描述了

2.hibernate基类
这个方法我是看开涛的《跟我学springmvc》看到的,感觉还有点用,在基类中定义好每个数据库访问类对应的基本查询语句,方便后续开发不用重复写,看代码

public class HibernateDaoImpl<T extends BaseEntity> extends HibernateDaoSupport
		implements HibernateDao<T>{

	protected final String COUNT_HQL = "select count(id) ";

	protected final String LIST_HQL;
	
	protected final String TABLE_NAME;

	/**
	 * 数据实体类型
	 */
	protected Class<T> entityClass;

	/**
	 * 默认构造函数
	 */
	@SuppressWarnings("unchecked")
	public HibernateDaoImpl() {
		Type superClassType = getClass().getGenericSuperclass();

		if (superClassType instanceof ParameterizedType) {
			Type[] paramTypes = ((ParameterizedType) superClassType)
					.getActualTypeArguments();
			this.entityClass = (Class<T>) paramTypes[0];
		}
		TABLE_NAME = this.entityClass.getSimpleName();
		LIST_HQL = "from " + this.entityClass.getSimpleName() + " where 1=1";
	}


通过 getClass().getGenericSuperclass()反射在父类的构造中获取到了子类传递的泛型

3.springmvc全局参数验证
参数为空的情况可能导致程序奔溃所以需要在程序中强制验证,但是文本参数的长度如果校验就显得有点累赘了,所以我通过反射封装了一个全局参数长度校验,在拦截器中插入即可

//对请求参数做校验(根据自定义验证注解)
    public boolean paramsValidate(BaseControler handler,HttpServletRequest request) throws Exception{
    	
    	//获取当前controll的所有方法
    	Method[] m = handler.getClass().getDeclaredMethods();
    	//遍历
    	for (int i = 0; i < m.length; i++) {
    		//获取RequestMapping注解
    		RequestMapping an = m[i].getAnnotation(RequestMapping.class);
    		//如果注解不是空的
    		if(an != null){
    			//把注解的值和当前请求的url做对比
    			String[] vs = an.value();
    			if(vs != null && vs.length > 0){
    				if(request.getRequestURI().endsWith(vs[0])){
    					//对比一致 获取当前方法的参数列表
    					@SuppressWarnings("rawtypes")
						Class[] c =  m[i].getParameterTypes();
    					for (int j = 0; j < c.length; j++) {
    						//如果当前参数是basebean的子类视为载体
							if(c[j].getSuperclass() != null && c[j].getSuperclass().equals(BaseBean.class)){
								
								Map<String, String[]> map = request.getParameterMap();
								
								for(String key : map.keySet()){
									//只对string类型的参数做校验
									Field f = c[j].getDeclaredField(key);

									//获取到当前字段的validation注解
									MyValidation valid = f.getAnnotation(MyValidation.class);
									String v1 = StringUtil.array2String(map.get(key));
									if(StringUtil.isEmpty(v1)){
										return true;
									}
									
									if(valid != null){
										//根据配置来验证参数
										int maxLen = valid.maxLen();
										if(v1.length() > maxLen){
											throw new Exception(f.getName() + " not accord with maxlenth");
										}
										
										String pattern = valid.pattern();
										if(!StringUtil.isEmpty(pattern)){
											Pattern p = Pattern.compile(pattern);
											Matcher matcher = p.matcher(v1);
											if(!matcher.matches()){
												throw new Exception(f.getName() + " not accord with pattern");
											}
										}
									}else{
										//按照默认的长度控制
										if(v1.length() > IConstans.PARAM_MAX_LEN){
											throw new Exception(f.getName() + " not accord with maxlenth");
										}
									}
									
									
								
								}
							}
						}
    				}
    			}
    		}
		}
    	return true;
    }

这个封装的关键点就在拦截器中操作类没人传递无法反射,但是拦截器中有当前访问的controller类和访问地址,所以我的思路是通过访问的地址链接来反射到controller类对应的@RequestMapping注解的方法,然后获取到该方法参数列表中类型为baseEntity子类的参数即是操作类,然后通过操作类获取字段及注解验证

4.全局埋点
这个功能我在前面的博客比较详细的说明了,主要还是在拦截器中以注解反射的方式来定位到用户的本次的操作记录到日志
@Override
	protected String doIntercept(ActionInvocation invocation) throws Exception {
		String result = null;
		try {
			//先执行action方法
			result = invocation.invoke();
			
			String enterMethod = invocation.getProxy().getMethod();
			//获取action方法上的WebOperateAnno 注解
			WebOperateAnno webOperateAnno = invocation.getAction().getClass().getMethod(enterMethod, new Class[0]).getAnnotation(WebOperateAnno.class);
			
			Object returnData = invocation.getAction();
			
			writeLog(webOperateAnno,returnData);
		} catch (Exception e) {
			sysLogger.error("操作日志记录失败",e);
		}
		
		
		return result;
	}


这种例子在程序中还有很多,目的就是做好封装减少程序员的编码量,如果以后面试的时候碰到面试官问你用java反射做了什么,或许你可以借鉴这些例子
分享到:
评论

相关推荐

    SparkWeb:SparkWeb是一个超轻量级的Java Web MVC框架

    Sparkweb 是一个超轻量级的简易高效的 Java WEB 开发框架,其设计思想结合了目前主流的 Spring、Struts2、Playframework、Nodejs-Expressjs、Ruby On Rails 等框架的优秀地方,完美支持 RESTful设计。 二、Sparkweb ...

    Java开发工程师简历模板

    - **Java核心技术**:列出你熟练掌握的Java语言特性,如面向对象编程、异常处理、多线程、集合框架、I/O流、反射等。 - **框架与库**:提及你熟悉的Java开发框架,如Spring、MyBatis、Hibernate等,以及你使用过的...

    2023java最新面试资料汇总

    面试题包括以下十九部分:Java 基础、容器、多线程、反射、对象拷贝、Java Web 模块、异常、网络、设计模式、Spring/Spring MVC、Spring Boot/Spring Cloud、Hibernate、Mybatis、RabbitMQ、Kafka、Zookeeper、MySql...

    狂神笔记,b站狂神说课程笔记大全(最新)

    b站狂神说课程笔记大全,每个部分都有 狂神说java系列笔记(java基础+javaweb+ssm+微服务)全套 狂神说上课笔记未删减 Java基础到技术升级 1、JavaSE:Java入门 ...28、SpringBootWeb开发提升(Swagger) 29、Spri

    java基础知识

    ### Java基础知识概述 Java是一种广泛使用的面向对象编程语言,由Sun Microsystems公司于1995年推出,...无论是进一步深入学习Java高级特性还是转向其他领域如Web开发、移动开发等,这些基础知识都是不可或缺的基石。

    javaOA办公系统模块设计方案.pdf

    - 使用Web在线流程设计器,允许用户通过图形化界面设计工作流。 - 可以预览流程XML,方便理解流程逻辑。 - 支持流程XML的导入与导出,便于流程的备份和迁移。 - 动态部署流程,实现快速响应业务需求。 2. **...

    Java-Projects

    "Java-Projects"这个标题暗示我们即将探讨的是与Java相关的项目,可能是为了学习、实践或者开发目的而创建的一系列代码示例或应用程序。这些项目可能涵盖Java的基础到高级用法,包括核心Java、多线程、网络编程、GUI...

    test_repo:学习

    13. **Java EE**:如果涉及到Web开发,Java EE(企业版)的Servlet、JSP、EJB等技术也是必须掌握的。 14. **现代Java特性**:随着Java版本的更新,新特性如Lambda表达式、Stream API、Optional类等引入,让代码更...

    spring-framework-learning-code:从0开始深入学习Spring小册子原始码-源码开源

    此外,源码阅读也能让我们了解Spring如何利用反射、动态代理等Java核心技术实现其功能。 在这个开源项目中,你将有机会逐行解析Spring的源代码,跟随作者的思路,逐步理解每个模块的设计理念和实现细节。这将是一个...

    NetCracker-JavaCourse

    Java被应用于各种领域,如Web开发、移动应用(尤其是Android)、企业级应用、大数据处理、云计算等。 在这个课程中,学习者可以期待涵盖以下Java编程的关键知识点: 1. **基础语法**:包括变量、数据类型、运算符...

    AndroidReactNativeWebview

    在Android开发中,React Native和WebView的结合使用可以带来丰富的用户体验和高效的开发流程。...然而,这也需要开发者具备扎实的Java、JavaScript基础,以及对React Native和Android原生开发的深入理解。

    ITC-7片段

    10. **Java反射**:反射机制允许程序在运行时检查类的信息,如类名、属性、方法等,并能动态调用方法和修改属性值,增强了代码的灵活性。 11. **Java集合框架的并发工具类**:如ConcurrentHashMap、...

Global site tag (gtag.js) - Google Analytics