历久弥新:SSH框架结构的简单优化过程
随手记录一下大学两年来对SSH框架的一些认识。
第一次接触到SSH框架是在大二的暑假,因为偶然的机会答应了老师使用SSH框架进行一个二手书交易网站的项目开发,由于第一次接触框架,只能简单的根据网络上各种简单的例子进行扩充(换种叫法:面向百度的编程),从而实现相应的功能。下面是项目在IDE里的结构图:
整个项目后端仅简单的分为了三大块:ACTION层负责业务处理和功能实现,DAO层为模型类以及POJO类和SERVICE层。简单的用PACKAGE来区分了层次,使得整个项目的结构显得非常繁琐,复杂。我想绝大部分初学者或者初次接触SSH框架的同学都会将框架搭建成上述的样子,然后就是在每个ACTION类里不断的添加各种五花八门的方法,去实现所需的功能。
简单的分析一下上面的结构存在的问题:
①Hibernate逆向生成的各种POJO类和实体类随意的糅合在了一个package下,而且只要你点开每一个表格对应的DAO类,里面的代码几乎都相似,都是对应表格的增删查改方法,代码重复率太高。
②Hibernate实体类映射文件也放在了DAO包下,不符合软件工程开发规范。
③Service层下每个接口及其实现类的方法近乎类似,大部分都是对应着查找单个记录,查找所有记录,以及增删查改的方法,均为直接调用的Dao层里的具体方法,使得Service层显得冗余,(几乎说可以直接删掉Service层,action类直接操作Dao中的方法也没问题)。
总的来说,代码重复率过高以及冗余,各层次实现功能不清晰是这次SSH框架结构上存在的问题。
那么具体里面的代码质量如何呢,下面就由部分截图来进行说明:
①首先先看Struts.xml文件:
由于当时对SSH框架理解不深,针对每一个Action类里面的方法,我均只配置了一个return的值“SUCCESS”,并且每一个方法我都在Struts.xml里添加了跳转目标,导致该文件看起来十分的凌乱,可改善的地方非常的多。
②查看Spring配置文件applicationContext.xml
上面第一个截图里的Spring配置毫无问题,分别是配置了数据源,开启事务以及hibernate层映射文件的引入,当然也是存在可以优化的地方。
但是第二个截图里的Spring配置我相信大家都能看出问题了,将Dao层里的DAO类以及Service类甚至是Action层中的action类均全部配置在了bean里。只要是熟悉SSH框架或SpringMVC的朋友都知道这是非常没必要的做法,导致配置文件过于长杂。因此这里是重点优化的地方。
③Action层中的一个具体方法展示:
1 package Action; 2 3 import java.util.List; 4 5 import javax.servlet.http.HttpSession; 6 7 import org.apache.struts2.ServletActionContext; 8 9 import Dao.Book; 10 import Dao.Page; 11 import Dao.Purchase; 12 import Dao.Shopcar; 13 import Dao.Users; 14 import Service.BookService; 15 import Service.PurchaseService; 16 import Service.ShopCarService; 17 18 import com.opensymphony.xwork2.ActionSupport; 19 20 public class ListItemAction extends ActionSupport { 21 /** 22 * 23 */ 24 private static final long serialVersionUID = 1L; 25 private List<Shopcar> list; 26 private Shopcar shopCar; 27 private ShopCarService shopCarService; 28 private Users users; 29 private Book book; 30 private BookService bookService; 31 private PurchaseService purchaseService; 32 private Purchase purchase; 33 34 public Purchase getPurchase() { 35 return purchase; 36 } 37 38 public void setPurchase(Purchase purchase) { 39 this.purchase = purchase; 40 } 41 42 public PurchaseService getPurchaseService() { 43 return purchaseService; 44 } 45 46 public void setPurchaseService(PurchaseService purchaseService) { 47 this.purchaseService = purchaseService; 48 } 49 50 private Page page; 51 52 public Page getPage() { 53 return page; 54 } 55 56 public void setPage(Page page) { 57 this.page = page; 58 } 59 60 public BookService getBookService() { 61 return bookService; 62 } 63 64 public void setBookService(BookService bookService) { 65 this.bookService = bookService; 66 } 67 68 public Users getUsers() { 69 return users; 70 } 71 72 public void setUsers(Users users) { 73 this.users = users; 74 } 75 76 public Book getBook() { 77 return book; 78 } 79 80 public void setBook(Book book) { 81 this.book = book; 82 } 83 84 public List<Shopcar> getList() { 85 return list; 86 } 87 88 public void setList(List<Shopcar> list) { 89 this.list = list; 90 } 91 92 public Shopcar getShopCar() { 93 return shopCar; 94 } 95 96 public void setShopCar(Shopcar shopCar) { 97 this.shopCar = shopCar; 98 } 99 100 public ShopCarService getShopCarService() { 101 return shopCarService; 102 } 103 104 public void setShopCarService(ShopCarService shopCarService) { 105 this.shopCarService = shopCarService; 106 } 107 108 // 往购物车中添加商品,并且检验是否有相同商品已经在购物车中 109 public String execute() throws Exception { 110 if (null == page) { 111 page = new Page(); 112 } 113 boolean b = true; 114 book = this.bookService.findByBookId(book.getBookId(), page).get(0); 115 HttpSession session = ServletActionContext.getRequest().getSession(); 116 this.users = (Users) session.getAttribute("user"); 117 this.list = this.shopCarService.findAllItems(this.users); 118 // 查询此书本是否已经存在于购物车中 119 for (Shopcar s : list) { 120 if (s.getBook().getBookId().equals(book.getBookId())) { 121 b = false; 122 } 123 } 124 if (b) { 125 this.shopCar.setBook(this.book); 126 this.shopCar.setUsers(this.users); 127 java.util.Date currentTime = new java.util.Date();// 将时间格式化,便于录入数据库 128 java.sql.Date date = new java.sql.Date(currentTime.getTime()); 129 this.shopCar.setAddDate(date); 130 this.shopCarService.save(this.shopCar); 131 return SUCCESS; 132 } 133 return ERROR; 134 135 } 136 137 // 将购物车的物品添加到确认支付的物品清单中 138 @SuppressWarnings("unchecked") 139 public String purchase() { 140 HttpSession session = ServletActionContext.getRequest().getSession(); 141 list = (List<Shopcar>) session.getAttribute("itemList"); 142 for (int i = 0; i < list.size(); i++) { 143 this.purchase = new Purchase(); 144 this.purchase.setBook(list.get(i).getBook()); 145 this.purchase.setBuyDate(list.get(i).getAddDate()); 146 this.purchase.setUsers(list.get(i).getUsers()); 147 this.purchase.setNum(list.get(i).getNum()); 148 this.purchaseService.save(purchase); 149 } 150 list.clear(); 151 session.setAttribute("itemList", list); 152 return SUCCESS; 153 } 154 155 // 购物车中的删除操作 156 public String delete() throws Exception { 157 this.shopCarService.delete(this.shopCar); 158 return SUCCESS; 159 } 160 161 // 显示某个用户的购物车 162 public String findByUserName() throws Exception { 163 HttpSession session = ServletActionContext.getRequest().getSession(); 164 users = (Users) session.getAttribute("user"); 165 this.list = this.shopCarService.findAllItems(this.users); 166 session.setAttribute("itemList", list); 167 return SUCCESS; 168 } 169 170 }
分析一下上述的action代码:
①私有化的成员变量为了保证成功调用增加的getter和setter方法使得代码篇幅过长,光成员变量的getter和setter方法代码占了100行,实际用于业务逻辑的代码才70行不到
②每一个具体的方法均只返回了SUCCESS类型,对于方法中产生的异常或者逻辑中需要处理对应问题没有添加对应的方法
③方法中开启了session链接,应该使用try和catch块,保证异常的处理
④方法命名没有达到规范
查看Service层及其实现层代码:
1 package Service; 2 3 import java.util.List; 4 5 import Dao.Users; 6 7 public interface UserService { 8 public List<Users> findAllUser(); 9 10 public void save(Users user); 11 12 public void delete(Users user); 13 14 public void update(Users user); 15 16 public Users findById(int id); 17 18 public List<Users> findByUsername(Object username); 19 }
......未完待续