OA的学习--第二天的内容--日志和BaseDao
来源:互联网 发布:c语言基本算法 编辑:程序博客网 时间:2024/05/18 03:15
现在写的是第二天的学习内容的总结,第一天是搭了SSH框架,并且将各个文件都进行了分包处理,今天的内容主要是1.接着昨天的,讲一下日志和log4j.properties的配置;2.抽取了BaseDao层的公共代码,用于对数据库进行增删改查;3.最后就是开始写一个功能,岗位管理,分析他的功能,分析出有多少请求和jsp文件,然后写代码.
鉴于第一天的总结太多了,有一部原因是我跟着视频,一步一步讲的,所以会把第一步怎么操作,第二步怎么操作都写下来,这样的好处就是以后我就可以按着这个步骤来做,坏处就是太多了.所以这次,我试试只是写最后结果.
日志
用Junit测试SpringTest的时候,会发现Console命令窗口中的初始化提示信息是红色的,这是因为没有配置日志.配置的日志可以是log4j,可以是JDK logging,也可以是自己写的自定义日志.但是,若有多个日志工具,用哪个呢?
可以用slf4j来控制,只要将slf4j和日志的jar(这是一个jar)放到项目中,他就会知道用哪个日志.这些jar可以在slf4j的文件夹中找到,如下图,若用slf4j-log4j12-1.6.1.jar,则表示用log4j日志,若添加slf4j-nop-1.6.1.jar则表示不用日志.并且slf4j的版本需要和slf4j-log4j的版本一样.并且每类日志的jar只能添加一个,否则slf4j就不知道如何处理了.
所以最后往项目中添加两个jar,log4j的jar以及slf4j和log4j的jar.然后提示就会变成黑色.
然后在log4j.properties资源文件中,配置日志的提示级别.级别有5个,从高到低,依次是fatal,error,warn,info和debug,若是配置为debug级别,则所有信息都会提示.若是fatal,则只有重大错误才会提示.其中这里配置的是,因为开发所以需要多多打印信息,这样好改Bug,所以给项目设置为debug,而除了项目以外的(如Spring等的),他们的一般信息都不需要打印出来,则只有error级别才显示.
### direct log messages to stdout ###log4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.Target=System.outlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n### set log levels - for more verbose logging change 'info' to 'debug' ####其他是error才报错log4j.rootLogger=error, stdout#cn.itcast.oa显示的级别是debug,但是其他的都是errorlog4j.logger.cn.itcast.oa = debug
DAO层
我们需要和数据库操作,这个就相当于我们的D层,不过java叫Dao层,这个层就是用来对数据库进行增删改查等各种与数据库的操作的.而且,由于每个实体都需要进行增删改查,所以在三层中每个实体都有一个Dao类.而为了灵活,会加上接口,那么就有接口和实现类,所以每个实体都有Dao接口和Dao实现类2个类.
并且由于实体的操作基本都有增删改查,代码也都类似,所以若是每个类都单着写,那么就会有很多类似的代码分布在各个类中.基于这个原因,所以提取一个BaseDao,采用泛型,反射,将最基本的增删改查封到里面.然后其他类就基础这个BaseDao,这样基本的增删改查就不用写了.代码化的表示就这样.
其中,各个接口的代码就不一一列举了,从上图中,就很容易看出该如何写代码了.主要是BaseDaoImpl类中,运用的泛型和反射.
像是这样,由于需要将数据写入到数据库中,所以需要session.而session,需要sessionFactory的getCurrentSesson()来获取,所以注入容器中的sessionFactory,@Resource,表示注入资源.而要spring注入sessionFactory,BaseDaoImpl实现类应该放在容器中.不过由于我们不用BaseDaoImpl的实例化对象,而是用他的子类,所以在子类上用@Repository注入就可以了.
然后增删改没有太大问题,对于查,由于需要知道传入T的真实类型,所以需要用反射,来获取真实的类型.做法就是在无参构造函数中,写上反射代码,获取真实的值.这样只要实例化子类对象,就能获取到子类对应实体的真实类型.若以RoleDaoImpl举例.继承BaseDaoImpl时,传入T为Role类型.然后this.getClass().getGenericSuperclass(),其中this就是RoleDaoImpl对象,然后获取结果pt的第一个参数的真实类型就可以了,因为只传入了一个T.若是传入Map类型,则key对应第一个参数,value对应第二个参数.写测试类,测试方法中只写一句代码 RoleDaoroleDao = new RoleDaoImpl();测试效果,结果为"clazz---> classcn.itcast.oa.domain.Role".
后面使用时,clazz.getSimpleName(),获取T的类名,得到Role这种值.
对于查询的结果,如返回集合结果,没有也不要返回null,最好返回一个空集合.但是若是返回new ArrayList()这种,它自带10个空间的数组,比较浪费空间,所以返回Collections.EMPTY_LIST就可以了.
public class BaseDaoImpl<T> implements BaseDao<T> {/** * 注入的factory */@Resourceprivate SessionFactory sessionFactory;private Class<T> clazz = null; public BaseDaoImpl() {// 使用反射技术得到T的真实类型// 获取当前new的对象的泛型的父类类型,得到一个泛型化的类型对象ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();// 获取第一个参数的真实类型this.clazz = (Class<T>) pt.getActualTypeArguments()[0];System.out.println("class --> " + clazz);}/** * 获取当前可用的Session,这样子类也可以用getSession()来获取session来实现自己的特殊方法. * * @return */protected Session getSession() {return sessionFactory.getCurrentSession();}public void save(T entity) {getSession().save(entity);}public void update(T entity) {getSession().update(entity);}public void delete(Long id) {Object obj = getById(id);if (obj != null) {getSession().delete(obj);}}public List<T> getByIds(Long[] ids) {if(ids == null || ids.length ==0 ) {return Collections.EMPTY_LIST;} else{return getSession().createQuery(//"FROM " + clazz.getSimpleName() + " WHERE id in (:ids)")//.setParameterList("ids", ids)//.list();}}public T getById(Long id) {if (id == null) {return null;} else {return (T) getSession().get(clazz, id);}}public List<T> findAll() {return getSession().createQuery(//"FROM " + clazz.getSimpleName())//.list();} }
而上面提到的作为继承了BaseDaoImpl的子类,用@Repository注解,表示放到容器中.里面不用写任何代码,就能实现增删改查了.
@Repositorypublic class RoleDaoImpl extends BaseDaoImpl<Role> implements RoleDao {}
最后在总结个类关系图.
岗位管理
现在Dao层已经建立好了,要做第一个功能,比较简单的岗位管理,分析业务需求,发现需要一个实体Role(岗位),以及基本方法增删改查.
操作流程,可以看这个表.先设计实体,然后分析功能,有几个请求,然后依次写Action,Service,Dao和JSP页面.
设计实体/建表
所以首先第一步,建立实体,分析字段,只需要Long型的id,和String类型的name和description(岗位说明),然后生成getter,setter方法.写映射文件Role.hbm.xml,主键为native策略,自增.其他是一般属性,很好写的.
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" > <hibernate-mapping package="cn.itcast.oa.domain"> <class name="Role" table="itcast_role"> <id name="id"> <generator class="native"></generator> </id> <property name="name"></property> <property name="description"></property> </class> </hibernate-mapping>
然后将该映射文件写到hibernate.cfg.xml中,然后就要创建表了,而什么时候会创建表呢?在创建sessionFactory的时候就会去检测和执行创建表.所以执行springTest的测试sessionFactory的测试方法,就可以创建表,这个里面就创建了sessionFactory.
<!-- 导入映射文件 --><!-- <mapping resource="cn/itcast/oa/domain/User.hbm.xml" /> --><mapping resource="cn/itcast/oa/domain/Role.hbm.xml" />
Action层
然后实体和表都建好了,分析功能,对应的请求.
分析,岗位管理,有一个岗位列表功能,可以查询所有的岗位;在列表页面上有添加,修改和删除的按钮,其中添加和修改都会弹到新页面,然后完成操作之后,点击提交,再重定向到列表页面.而删除是弹出提示框,询问是否确定删除,确定就删除.所以列表1个请求,添加/修改各2个请求,删除一个请求,所以共4个功能,6个请求,所以需要6个Action方法,每个Action方法处理一种请求.并且还需要3个页面,list页面,添加页面和修改页面(之后会将添加/修改合并成一个页面)
而其中添加/修改一定是重定向到列表页面,因为重定向是2个请求,会改变url的路径,而转发是一个请求,不会改变url路径,所以若添加完毕之后是转发到列表页面,那么此时url还是添加的url,刷新有可能就会将记录再添加一遍.
然后写Action代码,先分析,对于6个请求,都起上名字,他们的返回值字符串,有页面的需要在struts.xml配置对应页面,没有页面的,像是删除/添加/修改之后回到列表页面的,不能直接返回list到list.jsp页面,这样数据没有经过Action准备数据,页面是空的.所以需要写成"toList",然后配置为重定向到role_list,经过Action执行list()方法,再到list.jsp页面,就有数据了.
这幅图说明,所有的请求都应该经过Action来准备数据,再到JSP页面中去显示数据.
代码是这样的,Action中先是没有写Service调用的,只是最基本的方法.每个方法都只写了一句return "";
@Controller@Scope("prototype")public class RoleAction extends ActionSupport {/** * 列表 * * @return * @throws Exception */public String list() throws Exception {return "list";}/** * 删除 * * @return * @throws Exception */public String delete() throws Exception {return "toList";} //其他4个省略 }
然后配置struts.xml中的role的action.其中class为roleAction,应该是从spring容器拿到的.所以需要将Action放入到容器中.所以所有的Action上都要写上注解@Controller表示放入容器中,和@Scope("prototype"),表示该Action是多例的.
role_*表示匹配所有的岗位管理的请求操作,然后method中的{1},表示获取到第一个*号对应的值.若请求为role_list,则method为list,所以会执行RoleAction的list()方法.返回list方法返回"list"字符串作为result,再次经过Action被接收到,然后list对应list.jsp页面,所以数据会显示到list.jsp页面上.
<!-- 岗位管理 --><action name="role_*" class="roleAction" method="{1}"><result name="list">/WEB-INF/jsp/roleAction/list.jsp</result><result name="addUI">/WEB-INF/jsp/roleAction/addUI.jsp</result><result name="editUI">/WEB-INF/jsp/roleAction/editUI.jsp</result><result name="toList" type="redirectAction">role_list</result></action>
然后建立list页面和addUI和editUI共三个页面.每个页面只是写上"list","addUI",和"editUI",表明他们的名字,然后测试效果.启动tomcat,输入url,请求为role_list.action,会到list()方法上,最后显示list.jsp页面.同理addUI和editUI.
Service层
现在Action层的初步效果已经可以了,那么需要通过和数据库打交道,拿到数据真正的显示到界面上去.而一般采用的三层,Action和Dao中间,还有一层Service层.Action调用Service,Service调用Dao,Dao操作数据库,一层一层拿到数据.
所以在Action中的代码需要修改,首先由于需要Service,所以要建立Service接口和实现类各一个.而采用的又是注入的方式,所以Service的实现类必须交由容器来管理,用@Service来放到容器中,然后用service的findAll()方法,而Service的findAll方法内部,是去调用了Dao的findAll().最后将返回的集合,放到值栈的Map中,可以回显到JSP页面上,使用OGNL的#号就可以直接获取到.
然后对于删除,前台会传递一个id过来,然后根据id来删除岗位,而如何接收id?目前是通过直接写一个Long型的id,然后给他getter,setter方法,struts2就可以自动封装参数.
@Resourceprotected RoleService roleService;//获取删除时,前台传递过来的id值 private Long id; public Long getId() { return id; } public void setId(Long id) { this.id = id; }/** * 列表 * * @return * @throws Exception */public String list() throws Exception {List<Role> roleList = roleService.findAll();// 拿到集合,显示到页面,放在值栈中,获取用OGNL的#号ActionContext.getContext().put("roleList", roleList);return "list";}/** * 删除 * * @return * @throws Exception */public String delete() throws Exception {roleService.delete(id);return "toList";}
必须交由容器管理的Service的实现类就是这样.Service接口类就不介绍了.
并且除了需要交由容器管理,业务层还需要开事务,这样出了问题就会回滚了,所以还要写@Transactional,来开事务.然后里面是调用Dao层的各个方法,所以要注入roleDao,当然要注入roleDao,那么RoleDaoImpl一定也要交由容器管理,所以实现类上也写了@Repository.
所以我现在初步总结的是.都是交由容器来管理,让它来实例化,但是Action是写@Controller,Service是写@Service,Dao是写@Repository,则普通的pojo类是写@Component.并且Service和Dao的这个注解都是写在实现类上.还有被注入的对象的实现类,一定要在容器中,否则如何注入.
@Service@Transactionalpublic class RoleServiceImpl implements RoleService {@Resourceprivate RoleDao roleDao;public List<Role> findAll() {return roleDao.findAll();}public void delete(Long id) {roleDao.delete(id);}}
JSP页面
这样到目前为止,Action和Service,Dao都写完了,所以写JSP页面的内容,写list.jsp,将放到Map中的roleList的数据遍历显示到界面上.使用struts的标签,然后用标签的遍历器,遍历roleList,然后取出roleList中的Role对象的属性id,name和description,依次显示,删除则添加了role_delete的请求并带上参数id,而id的值通过%{id}获得,这是OGNL的写法.
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib prefix="s" uri="/struts-tags" %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <title>My JSP 'list.jsp' starting page</title> </head> <body> <s:iterator value="#roleList"> <s:property value="id"/> , <s:property value="name"/>, <s:property value="description"/>, <s:a action="role_delete?id=%{id}" onclick="return confirm('确定要删除吗?')">删除</s:a> <br/> </s:iterator> </body></head>
手动往数据库中写几条数据,然后效果就是这样,点击删除就会删掉数据.
以上就是第11集到18集的内容.内容不是很多,主要是说明了如何简单的加日志,同样是需要jar和配置文件.以及运用反射和泛型抽取BaseDao,达到代码复用.最后在这个的基础上,一步一步完成了岗位管理的findAll和删除功能.其中,抽取BaseDao,使用反射获取泛型的真实类型,感觉最重要.
总结,比第一天的应该短了不少了,有进步,继续努力.
- OA的学习--第二天的内容--日志和BaseDao
- OA的学习--第四天的内容--优化功能和页面
- OA的学习--第六天的内容--权限模块和论坛模块
- 学习Hibernate常用的BaseDao
- OA的学习--第五天的内容--优化和权限模块的初步功能
- OA的学习--第一天的内容--环境搭建
- OA的学习--第七天的内容--论坛模块
- 项目1:ItcastOA(2):日志说明、BaseDao和BaseDaoImpl的设计
- 万能的BaseDAO和注解的应用
- OA项目第二天:后端页面的显示
- JTV第二天的内容
- Hibernate常用的BaseDao
- BaseDao 的设置
- BaseDao的方法不起作用
- mybatis-basedao的实现
- SH整合的BaseDao
- baseDao的用法
- CRM-BaseDao的抽取
- 求10个数中最大值
- oc_study17--property的简便方式
- 黑马程序员_JAVA中IO流-字节流与字符流比较与转换
- 156 - Ananagrams
- 统治世界的十大算法
- OA的学习--第二天的内容--日志和BaseDao
- 一道水题 【strtok分解字符串】
- Unity iOS 基础 Unity iOS Basics
- ZigZag Convert
- 黑马程序员_日志集合类知识学习
- [SDOI2010星际竞速]解题报告
- C++_STL 各种容器
- iOS开发UI篇—控制器的View的创建
- Java实现双向链表