There is a lot of code, skip it and understand that logic is studying code
Introduce
Looking back at the projects in the previous section, the final hierarchy is:
On MVC, we analyze the advantages and disadvantages of MVC design mode, and add Service layer to deal with business logic, but this is not complete. For large projects, the program structure is still not clear enough, Service layer not only deals with business logic, but also with database operations; there are still the following problems:
- High coupling
- Poor code reusability
- The functional responsibilities of the Service layer are not single
DAO
To solve these problems, we need to further decouple the Service layer. How can we do this by increasing the data access layer DAO?
Definition:
DAO (Data Access Object), a data access object, refers to an object that provides CRUD functions on data; responsible for dealing with databases, between the business logic layer and the database;
Simply put:
It is to encapsulate the database operations originally in the Service layer into the DAO layer, so that the Service layer can concentrate on the processing of business logic and reduce the coupling between functions.
Hierarchy diagram after adding DAO:
Composition of DAO Layer
DAO is a design pattern for the data access layer and its complete components include the following:
It looks very complicated, yes, DAO is a complete solution for database operations, and if implemented according to the above structure, it is very standard for large business projects, but daunting for small, fast development projects
Old driver's advice: Over-design will make people unable to see the essence. When learning design mode, it is important to keep in mind the key issues you need to solve, and take the problem with you to see the role and importance of each part
Example
To better understand the nature of DAO, a simplified DAO design is used here.
Three objects in a DAO are required:
- Data Access Object (Bean)
- Database Connection Class
- DAO Implementation Class
The final Service layer needs DAO implementation objects, database connection objects exist to extract duplicate code, and beans already exist in the original system
Now you need two new classes, a DAO and a database connection class, to create them like this
DBTool:
Database connection class, responsible for connecting to the database, executing queries, and closing resources
package com.kkb.test; import java.sql.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class DBTool { //Default parameters public String ip = "127.0.0.1"; public int port = 3306; public String user="root", password="admin", charset ="utf8", dbName="db1"; private static boolean DriverLoaded=false; //Linking databases with default parameters public DBTool() throws ClassNotFoundException { if(DriverLoaded)return; try { Class.forName("com.mysql.jdbc.Driver"); System.out.println("DBTools message:Database Driver Loaded Successfully!"); } catch (ClassNotFoundException e) { System.out.println("DBTools Error:Driver Loading Failed!"); throw e; } DriverLoaded=true; } //Custom parameter initialization public DBTool(String ip, int port, String user, String password, String dbName) throws ClassNotFoundException { this(); this.ip = ip; this.port = port; this.user = user; this.password = password; this.dbName = dbName; } //Custom parameter initialization public DBTool(String user, String password, String dbName) throws ClassNotFoundException { this(); this.user = user; this.password = password; this.dbName = dbName; } //Get a link public Connection getConnection() throws SQLException { String url = String.format("jdbc:mysql://%s:%s/%s?characterEncoding=%s&user=%s&password=%s&useSSL=false",ip,port,dbName,charset,user,password); try { return DriverManager.getConnection(url); } catch (SQLException e) { System.out.println("DBTools Error Database Connection Failure!"); throw e; } } //Execute Query Statement public List<Map<String,Object>> executeQuery(String sql, Object...args) throws SQLException { ArrayList<Map<String, Object>> res = new ArrayList<>(); ResultSet resultSet = null; PreparedStatement preparedStatement = null; Connection connection = null; try { connection = getConnection(); preparedStatement = getPreparedStatement(connection, sql, args); resultSet = preparedStatement.executeQuery(); while (resultSet.next()) { resultSet.getMetaData().getColumnCount(); HashMap<String, Object> map = new HashMap<>(); for (int i = 1; i <= resultSet.getMetaData().getColumnCount() ; i++) { map.put(resultSet.getMetaData().getColumnName(i),resultSet.getObject(i)); } res.add(map); } } catch (SQLException e) { e.printStackTrace(); throw e; } finally { if(resultSet != null) resultSet.close(); if(preparedStatement != null) preparedStatement.close(); if(connection != null) connection.close(); } return res; } //sql parameter preprocessing private PreparedStatement getPreparedStatement(Connection connection, String sql, Object[] args) throws SQLException { PreparedStatement preparedStatement = connection.prepareStatement(sql); int count = sql.length() - sql.replace("?", "").length(); if(count != args.length){ throw new SQLException("DBTool Error: Number of parameters does not match"); } for (int i = 0; i < args.length; i++) { preparedStatement.setObject(i+1,args[i]); } return preparedStatement; } //Execute UPDATE statement public boolean executeUpdate(String sql,Object...args) throws SQLException { try { Connection connection = getConnection(); PreparedStatement preparedStatement = getPreparedStatement(connection, sql, args); int i = preparedStatement.executeUpdate(); if (i>0){return true;} } catch (SQLException e) { e.printStackTrace(); throw e; } return false; } }
UserDao:
Responsible for providing the required CURD methods for the Service Layer, essentially encapsulating the execution of SQL and the resolution of the results
package com.kkb.models; import com.kkb.test.DBTool; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Map; public class UserDao { private DBTool tools; //Constructor public UserDao() throws ClassNotFoundException { tools = new DBTool(); } //New Users public boolean insertUser(UserBean user) throws SQLException { String sql = "insert into user values(null,?,?)"; return tools.executeUpdate(sql, user.getName(), user.getPwd()); } //delete user public boolean deleteUser(UserBean user) throws SQLException { String sql = "delete from user where id = ?"; return tools.executeUpdate(sql, user.getId()); } //Update User public boolean updateUser(UserBean user) throws SQLException { String sql = "update user set name = ? , pwd = ? where id = ?"; return tools.executeUpdate(sql, user.getName(), user.getPwd(), user.getId()); } //Query all users public List<UserBean> queryAllUser() throws SQLException { ArrayList<UserBean> beans = new ArrayList<>(); List<Map<String, Object>> maps = tools.executeQuery("select *from user"); //To List for (Map<String, Object> temp : maps) { UserBean bean = getUserBean(temp); beans.add(bean); } return beans; } //map to bean method private UserBean getUserBean(Map<String, Object> temp) { UserBean bean = new UserBean(); bean.setId((Integer) temp.get("id")); bean.setName((String) temp.get("name")); bean.setPwd((String) temp.get("pwd")); return bean; } //Query by ID public UserBean queryUserByID(Integer id) throws SQLException { List<Map<String, Object>> maps = tools.executeQuery("select *from user where id = ?", id); //To List for (Map<String, Object> temp : maps) { UserBean bean = getUserBean(temp); return bean; } return null; } //Logon Authentication public UserBean checkLogin(UserBean login) throws SQLException { List<Map<String, Object>> maps = tools.executeQuery("select *from user where name = ? and pwd = ?", login.getName(), login.getPwd()); for (Map<String, Object> temp : maps) { UserBean bean = getUserBean(temp); return bean; } return null; } //Query by name public UserBean queryUserByName(String name) throws SQLException { String sql = "select *from user where name = ?"; List<Map<String, Object>> maps = tools.executeQuery(sql, name); if (!maps.isEmpty()){ return getUserBean(maps.get(0)); } return null; } }
UserService:
Instead of using JDBC, use UserDao to complete database operations
package com.kkb.srvices; import com.kkb.exceptions.LoginException; import com.kkb.models.UserBean; import com.kkb.models.UserDao; import java.sql.*; //User-related business logic public class UserService { private UserDao dao; public UserService() throws ClassNotFoundException { this.dao = new UserDao(); } //Method used to check login public UserBean checkLogin(UserBean reqBean) throws LoginException { //Determine whether the parameter is valid if(reqBean.getName() == null || reqBean.getPwd() == null || reqBean.getName().equals("") || reqBean.getPwd().equals("") ){ throw new LoginException("User name or password cannot be empty!"); }else { try { UserBean bean = dao.checkLogin(reqBean); if(bean != null) return bean; else throw new LoginException("ERROR Incorrect username or password!"); } catch (SQLException e) { e.printStackTrace(); throw new LoginException("The database is blown up!"); } } } }
Thus, using DAO (Data Access Object) to decouple the Service layer improves the maintainability of the code, but the complexity of the corresponding program also increases
Emphasize:
Methods in DAO s are not fixed and should be designed to meet specific business needs
MVC+DAO execution process:
What about factories and connections?
Design mode is like a double-edged sword, bringing scalability, maintainability, and other advantages, while the addition of design mode will make the program more complex
What we need to do is adopt the right design pattern in the right project
There are no factories and interfaces used in the above cases, so what should I do?
Analysis:
When the project reaches a later stage, the company makes a lot of money and wants to replace a stronger Oracle database, oracle's sql is slightly different, so you have to rewrite a new DAO implementation, and after that you have to look up all the places where UserDao is used, make all the changes, and you cry for the first time...
You're smart. You won't let this happen to you anymore, so you...... resigned!
Summary:
Since both methods are the same, only the SQL statements are different, extract an interface for them, define a factory class for creating objects, and modify the factory class to replace Dao's implementation class when you change the implementation class in the future
The overall structure is as follows:
If you finally provide a configuration file and let Factory go to the configuration file to get the type of Dao that needs to be created, everything will be perfect!
The MVC+Service+DAO design pattern is finished here
A Servlet handles requests for multiple different functions
Wait a moment. I can vaguely remember what problem in the first article wasn't solved?
The solution to this problem is simple:
First map the requests that need to be processed to the Servlet, and then select the corresponding processing method in the Servlet based on the request path.
Of course, there are different ways to match paths
Determine the path directly in the Servlet and call the method, (compare low)
Find a method that matches the path through reflection (method name is the same, limited)
Reflections + annotations allow the method name to be arbitrary and annotations provide the path (flexible, high-end)
SpringMVC takes the third approach
Want to write your own MVC framework? Come on.