JavaBean的属性命名和属性值注入的关系

进入JavaEE阶段后,我们的实体类(Model)都是以一个JavaBean的形式出现的,在使用框架等可以实现属性值的自动注入。


先说下什么是JavaBean,其实就是一个普通的类,但他有一些规范约束:

  • Ⅰ提供一个公有的无参构造函数.
  • Ⅱ需要被序列化并且实现了java.io.Serializable接口.
  • Ⅲ该类的属性一般是私有(private)修饰的.
  • Ⅳ可能有一系列的公有的"getter"或"setter"的访问器方法.
  • Ⅴ该类是一个公有类,并且用package语句声明属于某一个包.

划重点,要求属性值是被private修饰的,因此如果外界想要读写该属性,就必须通过getter/setter来操作,所以我们一般都会给JavaBean的属性生成对应的getter和setter。


那么今天这篇文章想讨论的是什么呢?
其实是关于属性命名的问题。是一个小细节,但也是一个新手坑。

我们知道,在Java中,遵循的变量命名规则是驼峰命名法,即变量名若由多个单词词根组成,那么变量名的首字母小写,遇到第二个单词词根时,该单词的首字母大写,之后小写…以此类推。
如:假设有个JavaBean的属性为name,那么它的getter的命名应该为:getName()。

别看这小小的命名规范没啥,到了JavaEE阶段,很多的框架对JavaBean的属性值的读写操作,都跟这有关。

举个栗子:

这几天在做项目的时候,在jsp页面用了EL表达式获取request域的page对象,想操纵下他的一个私有属性PageItems,如下:

  1. 先上JavaBean代码:
    JavaBean
    注意,划线部分的属性命名没有遵守驼峰命名法,第一个字母大写了。
    然后在该类中还提供了对应的getter/setter,如下:
    在这里插入图片描述
  2. 在Servlet中将page对象实例存储进了request域中,并请求转发到了jsp页面
protected void page(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        Integer pageNo = WebUtils.parseStringToInteger(request.getParameter("pageNo"), 1);
        Integer pageSize = WebUtils.parseStringToInteger(request.getParameter("pageSize"), Page.PAGE_SIZE);

        // 调用BookService获取本页的Page对象
        Page<Book> page = bookService.page(pageNo, pageSize);

        page.setUrl("manager/bookServlet?action=page");

        // 保存该page对象进request域
        request.setAttribute("page", page);
        // 请求转发到jsp中
        request.getRequestDispatcher("/pages/manager/book_manager.jsp").forward(request, response);
    }

以上代码,只需要关注有写注释的三条语句,分别是:获取page对象实例,存储进request域,将请求转发到jsp页面。

  1. 在jsp页面中用EL表达式,企图获取该page对象的PageItems属性
    在这里插入图片描述

  2. 一运行,诶好家伙,挂掉了…
    运行界面
    运行界面直接空白,查看下后台

  3. 后台打印了出错报告
    在这里插入图片描述
    在这里插入图片描述
    运行报错的原因,竟然是因为,找不到PageItems属性!!!博主那时候懵了一会,不知道怎么的,第一反应就是把EL表达式中的属性名的首字母改成小写,然后重新运行,结果如下:
    在这里插入图片描述
    成功运行了…玄乎
    并且,此时我并没有把JavaBean中的属性名也改成小写开头,也就是说,JavaBean中的属性名仍然是PageItems。

总结:
怎么说呢,就感觉还是要遵循Java的代码规范的。关于这个例子的解释,我个人理解如下:
首先,EL表达式获取Bean对象的属性,是通过调用该Bean对象的getXXX()来获取值的,其中的XXX是属性名。(ps:该属性值,甚至可以不存在!)
那么,对于一个规范的JavaBean的属性来说,如name,它所对应的getter是getName();如果不遵循规范,写成了Name,那么它对应的getter应该是什么呢?服务器不清楚。
接着,EL表达式中写bean对象.name,会去找该bean对象的getName();但是,如果写成了bean对象.Name,就无法找到对应的getter了,所以这也是服务器报错说找不到该属性的原因。

血的教训啊兄弟们!一定要遵守代码书写规范!



再来一个栗子:

做这个项目的时候呢,用了一下第三方的jar包,引入了一个类BeanUtils,其作用是自动将url请求中的参数列表自动封装进对应的bean对象实例中,就减少了我们自己从request对象中获取参数值后再调用bean对象的setter的繁琐操作。

/**
     * 封装请求参数进模型Bean中
     * @param obj 模型Bean对象
     * @param map 请求参数的map集合
     * @param <T> 待封装的Bean对象的具体类
     * @return 返回一个已封装好请求参数的bean对象实例
     */
    public static <T> T copyMapToBean(T obj, Map map){

        try {
            BeanUtils.populate(obj, map);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // BeanUtils的注入,是在原有的bean对象中进行注入的
        return obj;
    }

根据前面提到的,无论是手动注入bean对象的属性值,还是依靠第三方框架帮我们自动注入,其底层都是调用了该bean对象的setter来对属性进行值的注入


那么,开始实验:

  1. 首先,还是利用了上述的Page类,这次测试的属性值是PageTotal,其他的属性值遵守Java代码编写规则,如下:
    在这里插入图片描述

仍然在该类中提供所有属性的getter和setter方法。
并且提供了重写后的toString():
在这里插入图片描述

  1. 接着,从浏览器请求一个Servlet,并在请求中携带参数列表发送到服务器:
    在这里插入图片描述

  2. 在该Servlet中接收请求参数并打印,同时调用copyMapToBean()对bean对象的其他属性值进行自动注入,打印该bean对象:

/**
     * 分页功能
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    protected void page(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
    
   		// 省略了一些流程处理 ...
    
        System.out.println("pageSize = " + request.getParameter("pageSize"));
        System.out.println("PageTotal = " + request.getParameter("PageTotal"));
        Page<Book> bookPage = WebUtils.copyMapToBean(new Page<Book>(), request.getParameterMap());
        System.out.println("注入后的page对象:" + bookPage);

       // 省略了一些流程处理 ...
       
    }

结果如下:
运行结果截图

从运行结果可以看到,首先,Servlet中确实是接收到了两个参数,分别是pageSize和PageTotal。但在调用第三方类进行Bean对象的自动注入后,却发现被注入值的对象的属性中,只有pageSize成功注入,而PageTotal并没有注入成功。而实际的Bean对象实例中确确实实存在了该PageTotal属性,并且也有对应的setter。

  1. 将浏览器地址栏中的请求参数PageTotal修改成pageTotal,其他因素不变,再次访问服务器,查看运行结果:

神奇的事情发生了,注入成功了!!!第二行的输出结果之所以为null,是因为我没有改Servlet中获取请求参数的键名,仍然是"PageTotal",所以获取到的是null。但是,看注入后的结果,可以看到已经成功将pageTotal注入到bean对象中了,并且,注意了!此时的bean对象中的属性值其实是PageTotal,而不是pageTotal。



好了,做下这个栗子的总结:
  • 首先,如果是不遵循Java命名规范的变量,即使是有该变量值,也无法注入成功。
  • 其次,以setPageTotal()为例,其所对应的变量名为pageTotal,而不是PageTotal,这也就是为什么第一次注入会失败,而第二次注入成功的原因。在服务器看来,一个bean对象中的所有setter,都有其对应的属性存在,而该属性的名字就是setXXX()脱去set后的XXX的第一个字母改为小写,即为该setter所对应操纵的属性的属性名。



最后,做下全文总结:

  1. 这次举的两个例子,第一个是通过调用JavaBean的getter来操作bean对象的属性;第二个例子是通过调用setter来操作bean对象的属性。想说明的点,其实只有一个,就是在现成的框架或jar包中,对于一个JavaBean而言,getXXX()和setXXX()对应所关联的属性呢,其实都是以<脱去get/set后的XXX的第一个字母改为小写>为命名的属性。所以,无论是调用bean对象的getter还是setter,都要求调用者指定该属性为<脱去get/set后的XXX的第一个字母改为小写>为命名的属性,即使该属性与bean对象中真实存在的属性名不一致也无妨。
  2. Java变量命名规范为:驼峰命名法,且第一个字母必为小写,生成对应的getter和setter遵循驼峰命名法。
  3. 一定要遵守Java的各种书写规范啊兄弟们,可以避开很多坑的呜呜呜!





==========全文仅为个人观点,如有不妥,还请评论区指出。==========
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值