在web編程中,由於高內聚、低耦合的特點,需要將多個類實現多層,大致有以下幾層:
①entity,實體類,如user,role等,這些類里邊包含了私有屬性和公共的get、set方法這和數據庫中的表相對應,更嚴格一些,包括字段的順序和type都要保持一致。
②base,封裝了基本的操作數據庫的方法(增刪改查)
③dao,訪問並操作數據庫,若想從數據庫獲取數據,必須調用dao層。dao層沒有一點業務邏輯,全是跟數據庫操作有關的類
④service,業務邏輯層,里邊可以是接口。只要沒有訪問數據庫的操作,都寫到service層中。
舉個例子說明什么是業務。如做一個分頁功能,數據1000條,每頁20條,則可以把這個功能寫成工具類封裝起來,然后在業務層調用這個封裝的方法,這才是業務層要做的事。
service層和dao層有什么區別?
再舉個例子,如注冊用戶時,還想往日志表里添加一個日志,那么就要在業務層來實現這個操作,並對該操作添加事務,效果會更好。若不使用service,只用dao的話,那么就要連續使用userDao和logDao,那么萬一某一步出錯,就可能造成user加進去而log沒有添加成功。
⑤action,也就是原來的servlet,位於jsp和service層之間進行交互。主要的操作就是請求(request)和響應(response)。存取某個功能的整體實現方法。
以后不要在servlet中調用dao層,而要寫到serviceImpl(對接口的實現層)中,如以前的userServlet中有
private UserDao udao = new UserDaoImpl();//private必須寫
以后這一句要寫到UserServiceImpl內。
⑥vo,數據傳輸層,用來轉入轉出數據,跟前台有關。
⑦util,工具類,用來封裝一些公用的方法,如字符串的處理,字符集過濾等。
⑧impl,用來實現接口。一個接口可以有多種實現,用來滿足不同需要。
一般的調用情況如下:
貼一張很重要的圖,大致說明了各層的繼承和implements關系
舉一個小項目的例子,實現往數據庫增刪改查用戶。縮略圖如下:
其中User.java和UserVO.java現在看起來內容相同,區別在於User類是底層數據,一般不輕易改變。UserVO層業余數據庫中內容相對應,將DB中檢索出數據,或者要往DB中反映的數據保存在vo實例中。以后若想再有什么擴展,直接在VO層改就行,不用動底層代碼。
這里邊,UserDao,BaseDao,UserService都是接口類,相應的impl則是對其的實現。
1.BaseDao代碼:
- import java.util.List;
- /**
- * 基本的方法
- * @author Administrator
- *
- */
- public interface BaseDao<Entity> {
- /**
- * 保存
- * @param obj
- * @throws Exception
- */
- void save(Entity entity) throws Exception;
- /**
- * 刪除
- * @param id
- * @throws Exception
- */
- void delete(int id) throws Exception;
- /**
- * 更新
- * @param obj
- * @throws Exception
- */
- void update(Entity entity) throws Exception ;
- /**
- * 根據id查詢指定記錄
- * @param id
- * @return
- * @throws Exception
- */
- Entity findById(int id) throws Exception;
- /**
- * 查詢所有記錄
- * @return
- * @throws Exception
- */
- List<Entity> findAll() throws Exception;
- }
2.BaseDaoImpl代碼,利用反射獲取數據庫數據
- import java.lang.reflect.Field;
- import java.lang.reflect.Method;
- import java.lang.reflect.ParameterizedType;
- import java.sql.Connection;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.util.ArrayList;
- import java.util.List;
- import com.bjsxt.util.DBUtil;
- public class BaseDaoImpl<Entity> implements BaseDao<Entity> {
- protected Class clazz;
- public BaseDaoImpl(){
- ParameterizedType pz = (ParameterizedType) this.getClass().getGenericSuperclass();
- //利用反射返回當前類的父類的類型,並強制轉換
- clazz = (Class) pz.getActualTypeArguments()[0];
- //返回此類型實際類型參數的Type對象數組的第一個
- //這兩步的作用就是獲取父類泛型參數的實際類型
- System.out.println(clazz + "這是測試代碼,打印出來的");
- }
- @Override
- public void save(Entity entity) throws Exception {
- Connection conn = DBUtil.getConn();//連接數據庫
- String sql = "insert into " + clazz.getSimpleName() + " values(null";
- Field[] fs = clazz.getDeclaredFields();
- for (int i = 0; i < fs.length; i++) {
- sql += ",?";
- }
- sql = sql + ")";
- PreparedStatement ps = DBUtil.getPs(conn, sql);
- //user.setUsername(rs.getString("username"));
- for (int i = 0; i < fs.length; i++) {
- String methodName = "get" + Character.toUpperCase(fs[i].getName().charAt(0)) + fs[i].getName().substring(1);
- //假如有個實體user類,含有uname屬性,則獲取uname的方法默認會為getUname(),會將uname的首字母大寫,其余不變
- //Character.toUpperCase就是將字符大寫,然后將除首字母以外的截取出來,拼到一起,構成類似於getUname()的方法
- //user.setUsername(uForm.getUsername);
- //該處用get是因為要把對象保存進數據庫里,用get獲取屬性
- Method m = clazz.getDeclaredMethod(methodName);
- ps.setObject(i,m.invoke(entity));
- //setObject用來給"?"賦值。invoke則是在不知道具體類的情況下利用字符串去調用方法
- //正常情況下是user.getUsername,m.invoke(entity)中m是一個方法,類似於getUsername(),entity相當於user.
- //invoke是從實體里邊找方法,那句話的意思就是從實體里邊調用方法
- }
- ps.executeUpdate();
- DBUtil.close(ps);
- DBUtil.close(conn);
- }
- @Override
- public void view(Entity entity) throws Exception {
- // TODO Auto-generated method stub
- }
- @Override
- public void update(Entity entity) throws Exception {
- Connection conn = DBUtil.getConn();
- String sql = "update " + clazz.getSimpleName() + "set";
- Field[] fs = clazz.getDeclaredFields();
- for (int i = 0; i < fs.length; i++) {
- sql += fs[i].getName() + " = ?,";
- }
- sql = sql.substring(0,sql.length()-1) + " where id = ?"; //減去最后的逗號
- PreparedStatement ps = DBUtil.getPs(conn, sql);
- for (int i = 0; i < fs.length; i++) {
- String methodName = "get" + Character.toUpperCase(fs[i].getName().charAt(0)) + fs[i].getName().substring(1);
- Method m = clazz.getDeclaredMethod(methodName);
- ps.setObject(i, m.invoke(entity));
- }
- Method getId = clazz.getDeclaredMethod("getId");//更新需要知道id
- ps.setInt(fs.length, (Integer) getId.invoke(entity));//因為id在sql語句最后一個問號處,所以要用fs.length
- ps.executeUpdate();
- DBUtil.close(ps);
- DBUtil.close(conn);
- }
- @Override
- public void delete(int id) throws Exception {
- Connection conn = DBUtil.getConn();
- String sql = "delete from " + clazz.getSimpleName() + " where id = ?" + id;
- PreparedStatement ps = DBUtil.getPs(conn, sql);
- ps.executeUpdate();
- DBUtil.close(ps);
- DBUtil.close(conn);
- }
- @Override
- public Entity findById(int id) throws Exception {
- Connection conn = DBUtil.getConn();
- String sql = "select * from " + clazz.getSimpleName() + " where id= ? ";
- PreparedStatement ps = DBUtil.getPs(conn, sql);
- ps.setInt(1,id);
- ResultSet rs = ps.executeQuery();
- Entity entity = (Entity) clazz.newInstance();//利用無參構造函數新建實例
- Field[] fs = clazz.getDeclaredFields();
- if(rs.next()){
- for (int i = 0; i < fs.length; i++) {
- String methodName = "set" + Character.toUpperCase(fs[i].getName().charAt(0)) + fs[i].getName().substring(1);
- Method m = clazz.getDeclaredMethod(methodName, fs[i].getType());
- m.invoke(entity, rs.getObject(fs[i].getName()));
- }
- }
- DBUtil.close(rs);
- DBUtil.close(ps);
- DBUtil.close(conn);
- return entity;
- }
- @Override
- public List<Entity> findAll() throws Exception {
- Connection conn = DBUtil.getConn();
- String sql = "select * from " + clazz.getSimpleName();
- PreparedStatement ps = DBUtil.getPs(conn, sql);
- ResultSet rs = ps.executeQuery();
- List<Entity> enList = new ArrayList<Entity>();
- while(rs.next()){
- Entity en = (Entity) clazz.newInstance();
- //user.setUsername(rs.getString("username"));
- Field[] fs = clazz.getDeclaredFields();
- for (int i = 0; i < fs.length; i++) {
- String methodName = "set" + Character.toUpperCase(fs[i].getName().charAt(0)) + fs[i].getName().substring(1);
- Method m = clazz.getDeclaredMethod(methodName, fs[i].getType());
- m.invoke(en, rs.getObject(fs[i].getName()));
- }
- enList.add(en);
- }
- DBUtil.close(rs);
- DBUtil.close(ps);
- DBUtil.close(conn);
- return enList;
- }
- }
注意:String methodName在何處用get,何處用set
3.UserDao代碼
- import java.util.List;
- import com.bjsxt.base.BaseDao;
- import com.bjsxt.entity.User;
- public interface UserDao extends BaseDao<User>{
- List<User> findByPageList(int currentPage, int pageSize) throws Exception;
- Long getTotal() throws Exception;
- }
4.UserDaoImpl代碼
- import java.sql.Connection;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.util.ArrayList;
- import java.util.List;
- import sun.nio.cs.US_ASCII;
- import com.bjsxt.base.BaseDaoImpl;
- import com.bjsxt.dao.UserDao;
- import com.bjsxt.entity.User;
- import com.bjsxt.util.DBUtils;
- public class UserDaoImpl extends BaseDaoImpl<User> implements UserDao{
- @Override
- public List<User> findByPageList(int currentPage, int pageSize)
- throws Exception {
- Connection conn = DBUtils.getConn();
- String sql = "select * from user limit " + (currentPage-1)*pageSize + "," +pageSize;
- PreparedStatement ps = DBUtils.getPs(conn, sql);
- ResultSet rs = ps.executeQuery();
- List<User> userlist =new ArrayList<User>();
- while(rs.next()){
- User user = new User();
- user.setId(rs.getInt("id"));
- user.setUsername(rs.getString("username"));
- user.setPassword(rs.getString("password"));
- user.setAge(rs.getInt("age"));
- user.setSex(rs.getString("sex"));
- user.setBirthday(rs.getString("birthday"));
- user.setSalary(rs.getString("salary"));
- user.setDescription(rs.getString("description"));
- userlist.add(user);
- }
- DBUtils.close(rs);
- DBUtils.close(ps);
- DBUtils.close(conn);
- return userlist;
- }
- @Override
- public Long getTotal() throws Exception {
- Connection conn = DBUtils.getConn();
- String sql = "select count(*) from user";
- PreparedStatement ps = DBUtils.getPs(conn, sql);
- ResultSet rs =ps.executeQuery();
- if(rs.next()){
- return ((Number)rs.getInt(1)).longValue();
- }
- return ((Number)0).longValue();
- }
- }
5.User代碼,下邊的UserVO先和它一樣,就不貼了。
- public class User {
- private int id ;
- private String username ;
- private String password ;
- private int age ;
- private String sex ;
- private String birthday ;
- private String salary ;
- private String description ;
- public User() {
- super();
- // TODO Auto-generated constructor stub
- }
- public User(int id, String username, String password, int age, String sex,
- String birthday, String salary, String description) {
- super();
- this.id = id;
- this.username = username;
- this.password = password;
- this.age = age;
- this.sex = sex;
- this.birthday = birthday;
- this.salary = salary;
- this.description = description;
- }
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getUsername() {
- return username;
- }
- public void setUsername(String username) {
- this.username = username;
- }
- public String getPassword() {
- return password;
- }
- public void setPassword(String password) {
- this.password = password;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public String getSex() {
- return sex;
- }
- public void setSex(String sex) {
- this.sex = sex;
- }
- public String getBirthday() {
- return birthday;
- }
- public void setBirthday(String birthday) {
- this.birthday = birthday;
- }
- public String getSalary() {
- return salary;
- }
- public void setSalary(String salary) {
- this.salary = salary;
- }
- public String getDescription() {
- return description;
- }
- public void setDescription(String description) {
- this.description = description;
- }
- }
6.UserService代碼,只提供接口,不實現任何方法,只讓UserServiceImpl來實現
- import java.util.List;
- import com.bjsxt.util.DataGrid;
- import com.bjsxt.vo.UserVO;
- public interface UserService {
- void saveUser(UserVO userVO) throws Exception ;
- void deleteUser(int id) throws Exception ;
- void updateUser(UserVO userVO) throws Exception ;
- UserVO findById(int id) throws Exception ;
- List<UserVO> findAll() throws Exception ;
- DataGrid findByPage(int currentPage , int PageSize) throws Exception ;
- }
7.UserServiceImpl代碼,方法還沒完全實現,只完成一種。
- import java.nio.channels.DatagramChannel;
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.List;
- import com.bjsxt.dao.UserDao;
- import com.bjsxt.dao.impl.UserDaoImpl;
- import com.bjsxt.entity.User;
- import com.bjsxt.service.UserService;
- import com.bjsxt.util.DataGrid;
- import com.bjsxt.vo.UserVO;
- public class UserServiceImpl implements UserService {
- private UserDao userDao = new UserDaoImpl();
- @Override
- public void saveUser(UserVO userVO) throws Exception {
- }
- @Override
- public void deleteUser(int id) throws Exception {
- }
- @Override
- public void updateUser(UserVO userVO) throws Exception {
- }
- @Override
- public UserVO findById(int id) throws Exception {
- return null;
- }
- @Override
- public List<UserVO> findAll() throws Exception {
- return null;
- }
- @Override
- public DataGrid findByPage(int currentPage, int PageSize)
- throws Exception {
- List<UserVO> uservolist = new ArrayList<UserVO>();
- List<User> userList = this.userDao.findByPageList(currentPage ,PageSize);
- for (Iterator iterator = userList.iterator(); iterator.hasNext();) {
- User user = (User) iterator.next();
- UserVO uvo = new UserVO();
- uvo.setId(user.getId());
- uvo.setUsername(user.getUsername());
- uvo.setPassword(user.getPassword());
- uvo.setAge(user.getAge());
- uvo.setBirthday(user.getBirthday());
- uvo.setSalary(user.getSalary());
- uvo.setSex(user.getSex());
- uvo.setDescription(user.getDescription());
- uservolist.add(uvo);
- }
- Long total = this.userDao.getTotal();
- DataGrid datagrid = new DataGrid();
- datagrid.setRows(uservolist);
- datagrid.setTotal(total);
- return datagrid;
- }
- }
8.DataGrid代碼
- import java.util.List;
- public class DataGrid {
- private Long total ; //總記錄數
- private List rows ; //返回的數據條目
- public Long getTotal() {
- return total;
- }
- public void setTotal(Long total) {
- this.total = total;
- }
- public List getRows() {
- return rows;
- }
- public void setRows(List rows) {
- this.rows = rows;
- }
- }
9.DBUtil代碼
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- /**
- * 鏈接數據庫的
- * @author Administrator
- *
- */
- public class DBUtils {
- /**
- * 獲得connection對象
- * @return
- */
- public static Connection getConn(){
- Connection conn = null;
- try {
- Class.forName("com.mysql.jdbc.Driver");
- conn = DriverManager.getConnection("jdbc:mysql://localhost/ext_001", "root", "root");
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- } catch (SQLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return conn;
- }
- /**
- * 預編譯sql
- * @param conn
- * @param sql
- * @return
- */
- public static PreparedStatement getPs(Connection conn , String sql){
- PreparedStatement ps = null;
- try {
- ps = conn.prepareStatement(sql);
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return ps;
- }
- /**
- * 一系列關閉對象的close
- * @param conn
- */
- public static void close(Connection conn){
- if(conn != null){
- try {
- conn.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
- public static void close(PreparedStatement ps){
- if(ps != null){
- try {
- ps.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
- public static void close(ResultSet rs){
- if(rs != null){
- try {
- rs.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
- }
最后粘一篇百度知道上的內容,關於service層和dao層的,供參考。
首先,service層會很大,方法很多。
第二,試想,所有DAO都有增刪改查四個基本方法。假設在DAO層(如StudentDAO.java)里student.add(),student.delete().student.update(),student.query()。
而如果應用增加了service層(如ApplictionServiceImpl.java),需要在service層中加上
applicationService.addStudent(),deleteStudent(),updateStudent(),queryStudent()四個方法。
這時你需要更新service層的接口類ApplicationService.Java,加上這四個方法。然后再更新service層的實現類ApplicationServiceImpl,加上這四個方法,最后你發現這四個方法每個方法里都只有一句話(以addStudent()為例)
public int addStudent(Student student){
return student.add();
}
這樣是不是太傻了點,還不如在action中直接調用StudentDAO中的student.add()。
以上是我的個人看法,請各位指點
這么來講好了 按你所說 在action中直接調用StudentDAO中的student.add()。 現在有客戶A 客戶B
客戶A的需求是 addStudent 這個和你所說的情況一致
客戶B的需求是 addStudent 前去加一個動作 將學生父母的信息也插入數據庫
這時如果按照只調用DAO的方法的話,你需要從新建立一個action
CustomerBAction
再重新寫一個DAO 因為這個DAO里要有添加父母的方法 student.addStudentAndParentInfo()。
CustomerBAction 去調用 student.addStudentAndParentInfo()。
這樣加大了很多工作量
如果中間有service層的話 action始終用一個action
而調用的也是service接口 只要對接口注入不同的實現就可以滿足 不同客戶的需求了
知識要活學活用,要按照自己項目以后的發展趨勢來搭設環境,別人家說什么就用什么。其實有時候javabean+jsp 也很好用啊,因為jsp不用重啟服務 開發速度很快。我做小項目就是這種模式,以后小項目的更改也會很少,所以不用搭建的過於復雜。
補充:
entity和vo的不同還可以通過下邊這個例子說明。如有user.java和userVO.java
user的屬性為
- private int id ;
- private String username ;
- private String password ;
而userVO的屬性則可為:
- private int id ;
- private String username ;
- private String password1 ; //第一次輸入密碼
- private String password2 ; //確認密碼
在表單驗證時,password1和password2相同時才會被提交。這樣不用改entity類,只需修改vo層即可。當然,這里的password1和password2也得寫上get和set方法。