Technology Sharing

JavaWeb (Part 3: JDBC and MVC)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

JavaWeb (I: Basic knowledge and environment construction)icon-default.png?t=N7T8https://blog.csdn.net/xpy2428507302/article/details/140365130?spm=1001.2014.3001.5501JavaWeb (Part 2: Servlet and Jsp, Listener and Filter)icon-default.png?t=N7T8https://blog.csdn.net/xpy2428507302/article/details/140365159?spm=1001.2014.3001.5501

Table of contents

10. JDBC

1 Overview

2. Write a JDBC program

3. Detailed analysis

(1) Database URL

(2) Connection class

(3) Statement class

(4) ResultSet class

(5) Release resources

4. SQL injection issues

5.JDBC Transactions

6.JDBC Tools

7. Database connection pool

(1 Overview

(2) Use

8.DBUtils

11. MVC three-tier architecture

1 Introduction

2. MVC three-tier architecture


10. JDBC

1 Overview

JDBC (Java DataBase Connectivity): Java database connection technology

JDBC is a management system independent of a specific database and is a common interface for accessing and operating general SQL databases.

Defines a set of standards that provide a unified way to access different databases.

JDBC is an application API for database access, consisting of a set of classes and interfaces written in Java.

It includes two levels:

① Application-oriented API for programmers to call.

② Database-oriented API for manufacturers to develop database drivers.

JDBC connects to different databases by simply loading different database driver packages, without having to worry about differences in database operation languages.

2. Write a JDBC program

① Create database tables

  1. CREATE TABLE users(
  2. id INT PRIMARY KEY,
  3. `name` VARCHAR(40),
  4. `password` VARCHAR(40),
  5. email VARCHAR(60),
  6. birthday DATE
  7. );
  8. INSERT INTO users(id,`name`,`password`,email,birthday)
  9. VALUES(1,'张三','123456','[email protected]','2000-01-01');
  10. INSERT INTO users(id,`name`,`password`,email,birthday)
  11. VALUES(2,'李四','123456','[email protected]','2000-01-01');
  12. INSERT INTO users(id,`name`,`password`,email,birthday)
  13. VALUES(3,'王五','123456','[email protected]','2000-01-01');
  14. SELECT * FROM users;

② Import database dependencies

  1. <!--mysql的驱动-->
  2. <dependency>
  3. <groupId>mysql</groupId>
  4. <artifactId>mysql-connector-java</artifactId>
  5. <version>8.0.31</version>
  6. </dependency>

③ Use of JDBC:

Ⅰ. Load the database driver (the bridge between the Java program and the database)

Ⅱ. Get Connection, a connection between the Java program and the database

III. Create a Statement object to send SQL to the database, generated by Connection

IV. Write SQL statements (write different SQL statements according to business)

Ⅴ. Execute SQL (if you want to receive a return value, create a ResultSet object to save the query results after the Statement is executed)

VI. Closing the connection

  1. public class JDBCTest {
  2. public static void main(String[] args) throws Exception {
  3. //配置信息
  4. //要连接的数据库URL(解决中文乱码问题:useUnicode=true&characterEncoding=utf8&useSSL=true)
  5. String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
  6. //连接的数据库时使用的用户名
  7. String username = "root";
  8. //连接的数据库时使用的密码
  9. String password = "123456";
  10. Connection conn = null;
  11. Statement st = null;
  12. ResultSet rs = null;
  13. try {
  14. //1.加载驱动
  15. Class.forName("com.mysql.cj.jdbc.Driver");
  16. //2.获取与数据库的链接
  17. conn = DriverManager.getConnection(url, username, password);
  18. //3.获取用于向数据库发送sql语句的statement对象
  19. st = conn.createStatement();
  20. String sql = "select id,name,password,email,birthday from users";
  21. //4.向数据库发sql,并获取代表结果集的resultset对象
  22. //查:executeQuery 增删改:executeUpdate
  23. rs = st.executeQuery(sql);
  24. //5.取出结果集的数据
  25. while (rs.next()) {
  26. System.out.println("id=" + rs.getInt("id"));
  27. System.out.println("name=" + rs.getString("name"));
  28. System.out.println("password=" + rs.getString("password"));
  29. System.out.println("email=" + rs.getString("email"));
  30. System.out.println("birthday=" + rs.getDate("birthday"));
  31. }
  32. } catch (ClassNotFoundException e) {
  33. e.printStackTrace();
  34. } catch (SQLException e) {
  35. e.printStackTrace();
  36. } finally {
  37. try {
  38. //6.关闭链接,释放资源(先开后关)
  39. rs.close();
  40. st.close();
  41. conn.close();
  42. } catch (SQLException e) {
  43. e.printStackTrace();
  44. }
  45. }
  46. }
  47. }

3. Detailed analysis

(1) Database URL

jdbc:mysql://localhost:3306/xxx

jdbcprotocol
mysqlSub-protocol
localhost:3306Host:Port
xxxdatabase

Commonly used database URL address writing method:

  • Oracle writing: jdbc:oracle:thin:@localhost:1521:xxx
  • SqlServer写法:jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=xxx
  • MySql writing method: jdbc:mysql://localhost:3306/xxx

(2) Connection class

Connection is used to represent the connection to the database, and Collection is the most important object in database programming.

All interactions between the client and the database are completed through the connection object, the common methods of this object:

createStatement()Create a statement object that sends SQL to the database
prepareStatement(sql)Create a PrepareSatement object to send precompiled SQL to the database
setAutoCommit(boolean autoCommit)Set whether the transaction is automatically committed
commit()Committing a transaction on a link
rollback()Rollback transaction on this link

(3) Statement class

The Statement object is used to send SQL statements to the database. Common methods of the Statement object are:

executeQuery(String sql)Used to send query statements to data and return ResultSet result set
executeUpdate(String sql)Used to send insert, update, or delete statements to the database and return the number of rows updated in the database
execute(String sql)Used to send arbitrary sql statements to the database
addBatch(String sql)Put multiple SQL statements into one batch
executeBatch()Send a batch of SQL statements to the database for execution

Notice:

To improve operating efficiency, the execute method is generally not used directly.

Instead, use the corresponding methods: executeQuery for query and executeUpdate for addition, deletion and modification.

(4) ResultSet class

ResultSet is used to represent the execution results of Sql statements.

Resultset When encapsulating the execution result set, theSimilar to tableThe way

The ResultSet object maintains a cursor pointing to the table data row.Initially, the cursor is before the first row.

Calling the ResultSet.next() method can make the cursor point to a specific data row, and calling the getxxx method to obtain the data of that row.

① Get any type of data

getObject(int index)

Get the Object object according to the specified number of columns

getObject(string columnName)Get the Object object according to the specified attribute name

② Get data of a specified type, such as String type

getString(int index)

Get a String object according to the specified number of columns

getString(String columnName)Get a String object according to the specified attribute name

③ How to scroll the result set: 

next()Move to the next line
Previous()Move to the previous line
absolute(int row)Move to the specified line
beforeFirst()Move to the front of resultSet
afterLast()Move to the end of resultSet

(5) Release resources

After the Jdbc program is finished running, remember to release the objects that interact with the database created during the program running.

These objects are usually ResultSet, Statement, and Connection objects.

Especially the Connection object, which is a very scarce resource and must be released immediately after use.

If the Connection cannot be closed promptly and correctly, it may easily lead to system downtime.

To ensure that the resource release code can run, the resource release code must also be placed in the finally statement.

4. SQL injection issues

There are two problems when using Statement for development:

① Frequent string concatenation is required, resulting in a high error rate

  1. String username = "zhangsan";
  2. String password = "123";
  3. String sql = "select * from users where name='"+username+"' and password='"+password+"'";
  4. ResultSet rs = st.executeQuery(sql);

② There is a potential risk of SQL injection

SQL injection: Inject illegal SQL statements into the data entered by the user, use clever techniques to splice strings, cause SQL short circuit, and thus steal database data.

  1. public class SQLTest {
  2. public static void main(String[] args) throws Exception {
  3. // 正常登陆sql:select * from users where name='张三' and password ='123456'
  4. //login("张三","123456");
  5. // SQL 注入:select * from users where name='' and password ='123456' or '1'='1'
  6. login("", "123456' or '1'='1");
  7. }
  8. public static void login(String username, String password) throws Exception {
  9. String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
  10. String dbUsername = "root";
  11. String dbPassword = "123456";
  12. //1.加载驱动
  13. Class.forName("com.mysql.cj.jdbc.Driver");
  14. //2.获取与数据库的链接
  15. Connection conn = DriverManager.getConnection(url, dbUsername, dbPassword);
  16. //3.获取用于向数据库发送sql语句的statement
  17. Statement st = conn.createStatement();
  18. String sql = "select * from users where name='" + username + "' and password='" + password + "'";
  19. System.out.println(sql);
  20. //4.向数据库发sql,并获取代表结果集的rs
  21. ResultSet rs = st.executeQuery(sql);
  22. if (rs.next()) {
  23. System.out.println("登录成功");
  24. } else {
  25. System.out.println("登录失败");
  26. }
  27. //6.关闭链接,释放资源
  28. rs.close();
  29. st.close();
  30. conn.close();
  31. }
  32. }

operation result:

Notice:

In the SQL statement, and has a higher priority than or, so the executed SQL is equivalent to select * from users where '1' = '1';


Solution:Use the PreparedStatement subclass of Statement, which provides SQL placeholder functionality.

There is no need to concatenate strings, and the data entered by users will be fully checked, which is more secure.

  1. public class PSTest {
  2. public static void main(String[] args) throws Exception {
  3. // 正常登陆sql:select * from users where name='张三' and password ='123456'
  4. //login("张三","123456");
  5. // SQL 注入:select * from users where name='' and password ='123456' or '1'='1'
  6. login("", "123456' or '1'='1");
  7. }
  8. public static void login(String username, String password) throws Exception {
  9. String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
  10. String dbUsername = "root";
  11. String dbPassword = "123456";
  12. Class.forName("com.mysql.cj.jdbc.Driver");
  13. Connection conn = DriverManager.getConnection(url, dbUsername, dbPassword);
  14. //获取用于向数据库发送预编译sql语句的prepareStatement
  15. String sql = "select * from users where name = ? and password = ?";
  16. System.out.println(sql);
  17. PreparedStatement ps = conn.prepareStatement(sql);
  18. //给占位符 ? 填充数据
  19. ps.setString(1, username);
  20. ps.setString(2, password);
  21. ResultSet rs = ps.executeQuery();
  22. if (rs.next()) {
  23. System.out.println("登录成功");
  24. } else {
  25. System.out.println("登录失败");
  26. }
  27. rs.close();
  28. ps.close();
  29. conn.close();
  30. }
  31. }

operation result:

5.JDBC Transactions

A transaction refers to a logical set of operations, either all of which succeed or all of which fail (ACID principle).

When a Jdbc program obtains a Connection object from a database, by default this Connection object will automatically submit a transaction to the database.

If you want to turn off this default commit mode and execute multiple SQL statements in one transaction, you can use the following JDBC control transaction statement.

Connection.setAutoCommit(false);

Start transaction
Connection.rollback();Rollback Transaction
Connection.commit();Committing a transaction

① Create an account table

  1. /*创建账户表*/
  2. CREATE TABLE account(
  3. id INT PRIMARY KEY AUTO_INCREMENT,
  4. NAME VARCHAR(40),
  5. money DECIMAL(9,2)
  6. );
  7. /*插入测试数据*/
  8. insert into account(name,money) values('A',1000);
  9. insert into account(name,money) values('B',1000);
  10. insert into account(name,money) values('C',1000);

② Simulate the business scenario when the transfer is successful

  1. //失败后让数据库自动回滚事务
  2. public class Demo {
  3. public static void main(String[] args) {
  4. String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
  5. String username = "root";
  6. String password = "123456";
  7. Connection conn = null;
  8. try {
  9. Class.forName("com.mysql.cj.jdbc.Driver");
  10. conn = DriverManager.getConnection(url, username, password);
  11. //通知数据库开启事务,false表示开启
  12. conn.setAutoCommit(false);
  13. String sql1 = "update account set money=money-100 where name = 'A' ";
  14. conn.prepareStatement(sql1).executeUpdate();
  15. //模拟执行完SQL1之后程序出现了异常而导致后面的SQL无法正常执行,事务也无法正常提交
  16. int x = 1/0;
  17. String sql2 = "update account set money=money+100 where name = 'B' ";
  18. conn.prepareStatement(sql2)executeUpdate();
  19. //sql1 和 sql2都顺利执行,就提交事务
  20. conn.commit();
  21. System.out.println("成功!!!");
  22. } catch (Exception e) {
  23. //出现异常,通知数据库回滚事务
  24. conn.rollback();
  25. e.printStackTrace();
  26. } finally {
  27. conn.close();
  28. }
  29. }
  30. }

6.JDBC Tools

In different requests, you need to connect to the database and release resources each time, which will result in a lot of duplicate code.

Encapsulate the database connection preparation and release operations into a tool class and call it directly when using it to avoid writing duplicate code.

  1. public class JdbcUtil {
  2. private static Connection connection;
  3. private static String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
  4. private static String username = "root";
  5. private static String password = "123456";
  6. //驱动(类)只需要加载一次,放静态代码块即可
  7. static {
  8. try {
  9. //加载数据库驱动
  10. Class.forName("com.mysql.cj.jdbc.Driver");
  11. } catch (Exception e) {
  12. e.printStackTrace();
  13. }
  14. }
  15. // 获取数据库连接对象
  16. public static Connection getConnection() throws SQLException {
  17. return DriverManager.getConnection(url, username, password);
  18. }
  19. // 释放资源(利用多态:Statement 和 PreparedStatement 都可以传进来)
  20. public static void release(Connection conn, Statement st, ResultSet rs) {
  21. try {
  22. if (rs != null) {
  23. rs.close();
  24. }
  25. if (st != null) {
  26. st.close();
  27. }
  28. if (conn != null) {
  29. conn.close();
  30. }
  31. } catch (SQLException e) {
  32. e.printStackTrace();
  33. }
  34. }
  35. }

Call case, such as: add user

  1. public void add(String name, String password) {
  2. Connection conn = null;
  3. PreparedStatement ps = null;
  4. try {
  5. conn = JdbcUtil.getConnection();
  6. String sql = "insert into users(name,password) values(?,?)";
  7. ps = conn.prepareStatement(sql);
  8. ps.setString(1, name);
  9. ps.setString(2, password);
  10. ps.executeUpdate();
  11. } catch (SQLException e) {
  12. e.printStackTrace();
  13. } finally {
  14. JdbcUtil.release(conn, ps, null);
  15. }
  16. }

7. Database connection pool

(1 Overview

JDBC development process:

Ⅰ. Load the database driver (only need to load once)

Ⅱ. Establish database connection (Connection)

III. Create a Statement object to send SQL to the database, generated by Connection

IV. Writing SQL statements

Ⅴ. Execute SQL (query --&gt; ResultSet object receives result set)

VI. Close the connection and release resources


The database connection object is obtained through DriverManager. Each time it is obtained, it is necessary to apply to the database for connection and verify the username and password.

Each time a user makes a request, they need to obtain a connection from the database. However, creating a connection with the database usually consumes relatively large resources and takes a long time.

Each time a SQL statement is executed, the connection is disconnected, which causes a waste of resources and prevents the database connection resources from being reused well.

Assuming that the website has 100,000 visits a day, the database server will need to create 100,000 connections, which greatly wastes database resources and easily causes database server memory overflow and machine expansion.

Solution: Database connection pool

The basic idea of ​​​​the database connection pool:

Create a buffer pool for the database and put a certain number of connection objects into the buffer pool in advance.

When you need to obtain a database connection, you only need to take an object from the buffer pool.

After use, it is put back into the buffer pool for the next request, achieving resource reuse without the need for repeated creation.

When there are no idle connection objects in the database connection pool, new requests will enter the waiting queue and wait for other threads to release the connection.

(2) Use

JDBC's database connection pool is implemented using the javax.sql.DataSource interface, which is an interface officially provided by Java.

When using it, developers do not need to implement the interface themselves and can use third-party tools.

C3P0 is a commonly used third-party implementation. In actual development, you can directly use C3P0 to complete the operation of the database connection pool.

Steps for usage:

① Import dependencies in pom.xml

  1. <dependency>
  2. <groupId>com.mchange</groupId>
  3. <artifactId>c3p0</artifactId>
  4. <version>0.9.5.2</version>
  5. </dependency>

② Write code

  1. public class DataSourceTest {
  2. public static void main(String[] args) {
  3. try {
  4. //创建C3P0数据库连接池
  5. ComboPooledDataSource dataSource=new ComboPooledDataSource();
  6. dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
  7. dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8");
  8. dataSource.setUser("root");
  9. dataSource.setPassword("123456");
  10. //设置初始化连接个数
  11. dataSource.setInitialPoolSize(5);
  12. //设置最大连接个数(连接池中不够,可以继续申请,申请后最终的上限)
  13. dataSource.setMaxPoolSize(20);
  14. //当连接对象不够时,再次申请的连接对象个数
  15. dataSource.setAcquireIncrement(5);
  16. //设置最小连接数(当连接池中剩余2个连接对象时,就去申请 --> 提前做准备)
  17. dataSource.setMinPoolSize(2);
  18. Connection conn=dataSource.getConnection();
  19. //SQL操作...
  20. //将连接还回到数据库连接池中
  21. conn.close();
  22. } catch (PropertyVetoException e) {
  23. e.printStackTrace();
  24. } catch (SQLException e) {
  25. e.printStackTrace();
  26. }
  27. }
  28. }

Notice:

Connection obtained in the traditional way: com.mysql.cj.jdbc.ConnectionImpl@3c153a1

Connection obtained by C3P0: com.mchange.v2.c3p0.impl.NewProxyConnection@6156496

so,Although both methods call the close method, the implementation classes are different, so the method rewriting is also different. This is interface polymorphism.

The close method in C3P0 does not directly destroy the connection resources, but returns the connection to the database connection pool.


The above method of setting parameters for the database connection pool is written directly in the Java program.

This is the use ofhardcodeThe way,Each time you change the configurationRecompile required, generate new class files, the efficiency is too low

In actual development, the configuration information of C3P0 is defined in an XML file, and the Java program only needs to load the configuration file to complete the initialization operation of the database connection pool.

To modify the configuration later, just modify the configuration in xml without recompiling.

Steps for usage:

① In the resources directory, create a new file named c3p0-config.xml

② Fill in the configuration information in c3p0-config.xml:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <c3p0-config>
  3. <!--配置连接池mysql-->
  4. <named-config name="C3P0Test">
  5. <!-- 指定连接数据源的基本属性 -->
  6. <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
  7. <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbc?useUnicode=true&amp;characterEncoding=utf8</property>
  8. <property name="user">root</property>
  9. <property name="password">123456</property>
  10. <!-- 设置初始化连接个数 -->
  11. <property name="initialPoolSize">5</property>
  12. <!-- 设置最大连接个数(连接池中不够,可以继续申请,申请后最终的上限) -->
  13. <property name="maxPoolSize">20</property>
  14. <!-- 当连接对象不够时,再次申请的连接对象个数 -->
  15. <property name="acquireIncrement">5</property>
  16. <!-- 设置最小连接数(当连接池中剩余2个连接对象时,就去申请 -> 提前做准备) -->
  17. <property name="minPoolSize">2</property>
  18. </named-config>
  19. </c3p0-config>

③ Write Java programs

  1. public class DataSourceTest {
  2. public static void main(String[] args) {
  3. try {
  4. //创建C3P0数据库连接池
  5. ComboPooledDataSource dataSource=new ComboPooledDataSource("C3P0Test");
  6. Connection conn=dataSource.getConnection();
  7. System.out.println(conn);
  8. //将连接还回到数据库连接池中
  9. conn.close();
  10. }catch (SQLException e) {
  11. e.printStackTrace();
  12. }
  13. }
  14. }

Notice:

① The parameter in the ComboPooledDataSource constructor is the name attribute value of the named-config tag configured in c3p0-config.xml.

② At this time, the JDBC tool class can be modified as follows:

  1. public class JdbcUtil {
  2. private static DataSource dataSource;
  3. static {
  4. dataSource = new ComboPooledDataSource("C3P0Test");
  5. }
  6. // 获取数据库连接对象
  7. public static Connection getConnection() throws SQLException {
  8. Connection conn = null;
  9. try {
  10. conn = dataSource.getConnection();
  11. } catch (SQLException e) {
  12. e.printStackTrace();
  13. }
  14. return conn;
  15. }
  16. // 释放资源(利用多态:Statement 和 PreparedStatement 都可以传进来)
  17. public static void release(Connection conn, Statement st, ResultSet rs) {
  18. try {
  19. if (rs != null) {
  20. rs.close();
  21. }
  22. if (st != null) {
  23. st.close();
  24. }
  25. if (conn != null) {
  26. conn.close();
  27. }
  28. } catch (SQLException e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. }

8.DBUtils

  1. public static Student findById(Integer idx) {
  2. Connection conn = null;
  3. PreparedStatement st = null;
  4. ResultSet rs = null;
  5. Student stu = null;
  6. try {
  7. conn = JdbcUtil.getConnection();
  8. String sql = "select * from student where id = ?";
  9. PreparedStatement ps = conn.prepareStatement(sql);
  10. //给占位符 ? 填充数据
  11. ps.setInt(1, idx);
  12. rs = ps.executeQuery();
  13. //取出结果集的数据
  14. while (rs.next()) {
  15. Integer id = rs.getInt(1);
  16. String name = rs.getString(2);
  17. Double score = rs.getDouble(3);
  18. Date birthday = rs.getDate(4);
  19. stu = new Student(id, name, score, birthday);
  20. }
  21. } catch (SQLException e) {
  22. e.printStackTrace();
  23. } finally {
  24. try {
  25. //关闭链接,释放资源
  26. rs.close();
  27. st.close();
  28. conn.close();
  29. } catch (SQLException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. return stu;
  34. }

In the above code, it is too troublesome to fill the placeholders with data and retrieve the data from the result set.

If there are 100 attributes in the Student table, then we will have to write 100 rows in the while loop to fetch the data, and it may also take many rows to fill the placeholders.


Solution:DBUtils can help developers complete data encapsulation (mapping of result sets to Java objects).

Steps for usage:

① Import dependencies in pom.xml

  1. <dependency>
  2. <groupId>commons-dbutils</groupId>
  3. <artifactId>commons-dbutils</artifactId>
  4. <version>1.6</version>
  5. </dependency>

② Write code

  1. public static Student findById(Integer idx) {
  2. Connection conn = null;
  3. Student stu = null;
  4. try {
  5. conn = JdbcUtil.getConnection();
  6. String sql = "select * from student where id = ?";
  7. //使用DBUtils
  8. QueryRunner qr = new QueryRunner();
  9. stu = qr.query(conn, sql, new BeanHandler<>(Student.class), idx);
  10. } catch (SQLException e) {
  11. e.printStackTrace();
  12. } finally {
  13. try {
  14. //关闭链接,释放资源
  15. conn.close();
  16. } catch (SQLException e) {
  17. e.printStackTrace();
  18. }
  19. }
  20. return stu;
  21. }

At this point, filling the placeholder and retrieving the result set can be accomplished with two lines of code.

detail:

① The query method needs to pass in 4 parameters:

Connection Object

SQL Statements

ResultSetHandler interface implementation class object (the type of object to be converted: Student.class)

Fill in the placeholder parameters

② The ResultSetHandler interface is used to process result sets. It can convert the query result sets into Java objects and provides the following four implementation classes.

BeanHandlerMap the result set into a Java object (such as a Student object)
BeanListHandler Map the result set into a List collection (such as: List<Student > )
MapHandler

Map the result set into a Map collection object

(ie: Map<String,Object> key: attribute name; value: attribute value)

MapListHandler Map the result set into a MapList collection (ie: List <Map<<String,Object> &gt;)

③ The parameter that fills the placeholder is a variable parameter, so any number of parameters can be passed in to meet different user needs.

④ The converted object class (Student class) must have a no-parameter constructor, otherwise the program will report an error.

reason:The bottom layer finds this class through Student.class, and then throughReflection MechanismFind the no-argument constructor of the class and create its object.

⑤ The name of the attribute in the class must be exactly the same as the name of the field in the database table.

Because after the object is created, when assigning values ​​to the object attributes according to the result set, the search and assignment are performed according to the name.

11. MVC three-tier architecture

What is MVC?

  • Model: Model (service, dao, entity)
  • View: View (jsp, html, app client)
  • Controller: Controller (Servlet, Hander, Action)

After the request enters the Java Web application, the Controller receives the request, performs business logic processing, and finally returns the result to the user (View + Model).

1 Introduction

In the early years, for web application operations, users directly accessed the control layer, and the control layer could directly operate the database:

servlet--CRUD (create, delete, modify and check)--&gt;database

In the servlet code: processing requests, responses, view jumps, processing JDBC, processing business code, processing logic code

Disadvantages:The program is very bloated and not conducive to maintenance

solution: There is nothing that can't be solved by adding a layer. If there is, add another layer!

2. MVC three-tier architecture

Model

  • Business processing: business logic (Service)
  • Data persistence layer: CRUD (DAO data persistence object)

view

  • Displaying data
  • Provide a link to initiate a Servlet request (a, form, img...)

Controller (Servlet)

  • Receive user request: (req, request parameters, session information)
  • Hand over the corresponding code to the business layer
  • Control view jump

Take user and administrator login as an example:

Controller layer:

  1. @WebServlet("/login")
  2. public class LoginServlet extends HttpServlet {
  3. private LoginService loginService = new LoginServiceImpl();
  4. /* 处理登录的业务逻辑*/
  5. @Override
  6. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  7. String username = req.getParameter("username");
  8. String password = req.getParameter("password");
  9. String type = req.getParameter("type");
  10. Object object = loginService.login(username,password,type);
  11. if(object != null){
  12. HttpSession session = req.getSession();
  13. switch (type){
  14. case "reader":
  15. Reader reader = (Reader) object;
  16. session.setAttribute("reader",reader);
  17. //跳转到用户的首页
  18. resp.sendRedirect("/book?page=1");
  19. break;
  20. case "admin":
  21. Admin admin = (Admin) object;
  22. session.setAttribute("admin",admin);
  23. //跳转到管理员的首页
  24. resp.sendRedirect("/admin?method=findAllBorrow&page=1");
  25. break;
  26. }
  27. }else{
  28. resp.sendRedirect("login.jsp");
  29. }
  30. }
  31. }

Service layer:

  1. public interface LoginService {
  2. //利用多态,动态返回不同类型的对象
  3. public Object login(String username,String password,String type);
  4. }
  1. public class LoginServiceImpl implements LoginService {
  2. private ReaderRepository readerRepository = new ReaderRepositoryImpl();
  3. private AdminRepository adminRepository = new AdminRepositoryImpl();
  4. @Override
  5. public Object login(String username, String password,String type) {
  6. Object object = null;
  7. //业务逻辑处理:根据type的值,来选择调用不同的登录方法,去查找不同的表
  8. switch (type){
  9. case "reader":
  10. object = readerRepository.login(username,password);
  11. break;
  12. case "admin":
  13. object = adminRepository.login(username, password);
  14. break;
  15. }
  16. return object;
  17. }
  18. }

Dao / Repository Layer:

  1. public interface AdminRepository {
  2. public Admin login(String username,String password);
  3. }
  1. public interface ReaderRepository {
  2. public Reader login(String username,String password);
  3. }
  1. public class AdminRepositoryImpl implements AdminRepository {
  2. //管理员的登录方法(和数据库交互)
  3. @Override
  4. public Admin login(String username, String password) {
  5. Connection connection = JDBCTools.getConnection();
  6. String sql = "select * from bookadmin where username = ? and password = ?";
  7. PreparedStatement statement = null;
  8. ResultSet resultSet = null;
  9. Admin admin = null;
  10. try {
  11. statement = connection.prepareStatement(sql);
  12. statement.setString(1,username);
  13. statement.setString(2,password);
  14. resultSet = statement.executeQuery();
  15. if(resultSet.next()){
  16. admin = new Admin(resultSet.getInt(1),resultSet.getString(2),resultSet.getString(3));
  17. }
  18. } catch (SQLException e) {
  19. e.printStackTrace();
  20. } finally {
  21. JDBCTools.release(connection,statement,resultSet);
  22. }
  23. return admin;
  24. }
  25. }
  1. public class ReaderRepositoryImpl implements ReaderRepository {
  2. //用户的登录方法(和数据库交互)
  3. @Override
  4. public Reader login(String username, String password) {
  5. Connection connection = JDBCTools.getConnection();
  6. String sql = "select * from reader where username = ? and password = ?";
  7. PreparedStatement statement = null;
  8. ResultSet resultSet = null;
  9. Reader reader = null;
  10. try {
  11. statement = connection.prepareStatement(sql);
  12. statement.setString(1,username);
  13. statement.setString(2,password);
  14. resultSet = statement.executeQuery();
  15. if(resultSet.next()){
  16. reader = new Reader(resultSet.getInt(1),resultSet.getString(2),resultSet.getString(3),resultSet.getString(4),resultSet.getString(5),resultSet.getString(6),resultSet.getString(7));
  17. }
  18. } catch (SQLException e) {
  19. e.printStackTrace();
  20. } finally {
  21. JDBCTools.release(connection,statement,resultSet);
  22. }
  23. return reader;
  24. }
  25. }