近来整理三年前有关Java SSH(Struts+Spring+Hibernate)的后台开发工作。
【当年也是写Java比C++多的,现在已经转成C++方向了】。
2012年8月本人有幸和五人西瓜子小团队在无锡的全国大学生软件服务外包创新创业大赛获得小奖。
项目名为“逍遥游”自助旅游系统 是一套基于Android用户的景区智能导游、智慧导航、自助旅游系统。搭建景区服务器收集游客位置等信息方便景区管理。
以该项目为例,简单介绍SSH的后台开发。后台开发代码见https://github.com/fanxiang090909/Carefree-Tour-Guide
一。概述
小型Java EE服务器框架一般分为四层。
1 ) 数据库表实体对象层
2 ) 数据访问接口层(Hibernate接口)
3 ) 逻辑业务代码层(完全自定义,为把业务逻辑抽象出来,增加代码复用)
4 ) http响应处理层(servlet或struts2)
当然某些十分简单的处理也可比必要抽象出业务逻辑代码,只需在servlet或struts2中完成全部功能即可。
后台的处理全部是由servlet或struts2的action处理。没有在servlet用到自定义过滤器以及重定向等等东西,也没有在action中用到拦截器(文件上传下载除外)
比如在url为/xxxxx/login.do中调用LoginServlet来处理LoginServlet中需要调用验证用户名密码的业务逻辑类ValidateLogin中的方法,则需要私有属性,这里把它定义为静态,节省空间
/**
* 验证用户登陆服务属性,在service,业务逻辑层定义
*/
private static ValidateLoginvalidateLogin;
/**
* 构造方法
*/
public LoginServlet() {
super();
LoginServlet.validateLogin = newValidateLogin();
}
ValidateLogin逻辑业务类中有如下方法验证用户是否注册,其中tourDao是数据访问接口层。
在业务逻辑层尽量把所有的下层异常处理干净,返回给servlet或action的只是业务处理后的结果,成功或失败
/**
* 验证登陆
*@param username 用户名
*@param passwd 密码
*@return 0 成功, 1没有这个用户名, 2密码错误
*/
public int hasRegistered(String username,String passwd) {
Tourist currentTourist = tourDao.findByTouristId(username);
/* 如果不为空,继续验证密码 */
if (currentTourist != null) {
if(passwd.equals(currentTourist.getPasswd()))
return0;
else
return 2;
} else {
return 1;
}
}
数据访问接口TouristDAO中有查找Tourist的方法
public Tourist findByTouristId(Stringtouristid) {
/* hibernate 会话打开 */
Session session =HibernateUtil.getSessionFactory().openSession();
/ *
*事务开始,
*hibernate中的一切数据库操作都要有手动的事务开始和结束
*/
Transactiontx = session.beginTransaction();
/* 这一步也可以用sql语句替换,每个sql语句都在query末尾添加匹配实体对象addEntity,如下 */
/* Queryquery = session.createSQLQuery
("SELECT t.* FROM tourist t WHERE t.tour_id = :tour_id").addEntity(Tourist.class);
*/
Tourist entity = (Tourist) session.get(Tourist.class,touristid);
/* 事务提交 */
tx.commit();
return entity;
}
Hibernate创建数据库表并且映射到java对象:
所有的映射关系可以由配置文件xxxxx.hbm.xml中定义(一个实体类一个配置文件)或由hibernate的注解Annotation方式定义
主要分为主键的映射
属性的映射
关联映射
其中数据库表的一对一的关联
可映射为一个对象中含有类型为另一对象的私有属性(单项一对一).
可映射为双方实体对象都含有类型为另一对象的私有属性(双向一对一)
数据库表的一对多关联
可映射为“一“的一方中含有类型为“多”一方集合的私有属性
可映射为“多“的一方中含有类型为“一”一方的私有属性
在双方分别配置单向一对多和单向多对一即为双向一对多关联
数据库实体的多对多关联
二。整体设计
一共定义如下多数据访问接口,每一接口除update(Entity entity)
Save(Entity entity)
Delete(Entity entity)方法外额外需要写必要的一个或多个findXXX方法
当然名字可以随便起,这几个方法对应的是数据库操作的增删改查
数据库操作CRUD --- 增加Create、查询Retrieve、更新Update、删除Delete
每一个方法包括update、save、delete都可以不调用hibernate提供的接口而是手动写sql语句实现,当然每写一个query =session.createSqlQuery(“sql语句”)需要query.execute()来执行sql,否则光写transaction.commit()也不会执行。
如AdminDAO中:
public AdminfindByUsername(String username);
CommentDAO中
/**
* 查找某一景点的某页评论列表
* 按从最近到最早顺序排序
* @param indexOfPage 第几页,从1-?
* @param spot_id 景点号
* @return 查找spot_id景点indexOfPage评论列表
*/
publicList
FriendDAO中
/**
* 找我的好友
* @param myusername
* @return Friend的类list
*/
publicList
ProductDAO中
/**
* 查找某一景点的某页价格列表
* 按从最近到最早顺序排序
*/
publicList
SpotDAO定义了一个枚举类型和两个重要方法
/* 景点类型,枚举类型 */
enum SpotType{
ScenicSpot,
ThemeSpot,
EatingSpot,
HotelSpot,
RestSpot,
Toilet,
Gate
};
/* 得到某一景区的所有类型为Type的景点 */
public List
/*得到景点*/
public Spot findSpotById(Long id);
TouristRouteDAO中方法较多
/.* 得到最近所有游客的位置*/
public List
/* 得到某一游客当前位置*/
public TouristRoutePointfindTouristRouteCurrentPoint(String tourname);
/* 得到某一游客的一天内路线*/
public List
/* 删除某游客的当某天的路线记录点*/
public void deleteTouristPoints_OneDay(Stringusername, Date day);
/* 删除某游客的所有路线记录点*/
public void deleteTouristPoints_All(Stringusername);
业务逻辑层
|
CommentService中
/* 发送评论,调用数据访问接口CommentDAO的save方法
* 返回0评论成功,1。。。2。。。3等各种错误,评论失败(自己定义),
* 方便在servlet或action中处理返回
*/
public intsendComment(String username, String comment, Float commentGrade, long spotid,String nickname)
FeedbackService中
/* 发表反馈,调用数据访问接口FeedbackDAO的save方法 */
public intsendFeedback(String username, String feedback, int gardenid)
FriendService中
/* 得到某人的好友 */
publicList
Http响应层Servlet或struts的action
其中admin中
tourist中
均为获得业务逻辑中的返回true或false或是int类型的0,1,2等等做相应处理返回json或普通文本格式,需要注意的是编码
后台开发代码见https://github.com/fanxiang090909/Carefree-Tour-Guide