構建web應用之——SpringMVC實現CRUD
配置好SpringMVC最基本的配置後,開始實現處理資料的CRUD(CREATE, READ, UPDATE, DELETE)
為實現模組上的鬆耦合,我們將與資料庫的互動任務交給DAO(Data Access Object,即資料訪問物件)層,
SpringMVC中使用@Repository註解為DAO自動生成bean,下面是實現資料增刪改查所用的資料庫:
1.資料庫:mysql
2.資料來源連線池:DBCP(最先使用了Spring中內建的基於JDBC的資料來源DriverManagerDataSource,但它沒有
池的概念,在每次請求連線時都要建立新連線,降低了效能)
實現過程:
一、新增依賴
基於之前的專案,我們還需要配置一些其他的依賴,來支援我們專案的構建,具體依賴如下:
<!-- mysql --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.3.RELEASE</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.13</version> <scope>runtime</scope> </dependency> <!-- 資料來源連線池 --> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>commons-pool</groupId> <artifactId>commons-pool</artifactId> <version>1.6</version> </dependency>
除了上述依賴意外,我們還需要加入spring bean的依賴。雖然我們使用註解自動裝配以及XML配置的形式來宣告和使用bean,
但是,我們需要spring bean來配置我們的配置檔案路徑。
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.1.3.RELEASE</version> </dependency>
二、編碼(Service層和Controller層的實現)
我們通過DAO層來與資料庫實現互動,因此,我們的Service層以及Controller層無需關注資料互動,只需要處理自己本職的工作即可。
下面是檔案結構:
我們通過StudentController類來響應請求,通過StudentService介面來定義CRUD四種服務,通過StudentDao介面來定義
與資料庫互動的方法(增、刪、改、查),StudentServiceImpl類以及StudentDaoImpl類分別實現了介面中定義的方法。
StudentDao定義與資料庫互動的方法(具體實現過程拋給其實現類):
package example.dao; import example.entity.Student; public interface StudentDao { public void create(Student student); public Student readById(String studentId); public void updateName(String studentId, String newUsername); public void deleteById(String studentId); }
有了StudentDao中定義的方法後,我們就可以編寫Controller層和Service層程式碼邏輯了(資料如何增刪改查我們暫時不用關心)
StudentService定義了我們的web專案所要擁有的功能:
1.新增一個學生
2.查詢指定學號的學生資訊
3.更新學生資訊
4.刪除指定學生
package example.service; import example.entity.Student; public interface StudentService { public void create(Student student); public Student readById(String studentId); public void updateUsername(String studentId, String newName); public void deleteById(String studentId); }
StudentServiceImpl實現了StudentService介面中的方法
package example.service; import example.dao.StudentDao; import example.entity.Student; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.ComponentScan; import org.springframework.stereotype.Service; @Service public class StudentServiceImpl implements StudentService { // 注入StudentDao @Autowired private StudentDao studentDao; @Override public void create(Student student) { studentDao.create(student); } @Override public Student readById(String studentId) { return studentDao.readById(studentId); } @Override public void updateUsername(String studentId, String newName) { studentDao.updateName(studentId, newName); } @Override public void deleteById(String studentId) { studentDao.deleteById(studentId); } }
使用@Service註解使得Spring自動為StudentService生成bean,同時我們注入了StudentDao的bean
Controller層負責處理請求:
package example.controller; import example.entity.Student; import example.service.StudentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.ComponentScan; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; @Controller @RequestMapping("/student") public class StudentController { // 注入StudentService Bean @Autowired private StudentService studentService; // 處理建立學生請求 @RequestMapping(value = "/create", method = RequestMethod.POST) public String createStudent(Student student) { studentService.create(student); // 重定向到學生資訊介面 return "redirect:/student/read/" + student.getStudentId(); } // 處理查詢學生資訊請求 @RequestMapping(value = "/read/{studentId}", method = RequestMethod.GET) public String readStudent( @PathVariable("studentId") String studentId, Model model) { model.addAttribute(studentService.readById(studentId)); return "student"; } // 處理JSP檢視查詢處理 @RequestMapping(value = "/read", method = RequestMethod.GET) public String readStudentByView( @RequestParam("studentId") String studentId, Model model) { model.addAttribute(studentService.readById(studentId)); return "student"; } // 處理修改學生資訊請求 @RequestMapping(value = "/update", method = RequestMethod.POST) public String updateStudent(String studentId, String newUsername) { studentService.updateUsername(studentId, newUsername); return "redirect:/student/read/" + studentId; } // 處理刪除學生請求 @RequestMapping(value = "/delete", method = RequestMethod.POST) public String deleteStudent(String studentId) { studentService.deleteById(studentId); return "deleteSuccessfully"; } }
@Controller註解使Spring自動為其生成bean,@RequestMapping註解用來宣告請求對映(類比之前的helloMVC實現)
最後,我們需要在DispatcherServlet以及Spring內部配置檔案中進行配置,使其能夠在編譯時掃描到帶有註解的類併為其生成bean
dispatcher-servlet.xml中
<!-- DispatcherServlet上下文只管理@Controller型別的bean --> <context:component-scan base-package="example"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 自動掃描裝配 --> <context:component-scan base-package="example.controller"/>
applicationContext.xml
<!-- 忽略對@Controller的掃描 --> <context:component-scan base-package="example"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
三、實現Dao層
到目前為止,我們還無法獲取資料(當然可以在StudentDaoImpl中使用靜態資料),接下來我們要實現StudentDao介面中
的方法,使得我們能真正意義上在檢視中看到想要的資料
在編寫方法邏輯之前,我們需要完成資料庫相關配置:
1.資料庫配置引數(jdbc.properties)鬆耦合的一種方式
############ DBCP資料來源連線池配置 ############ mysql jdbc.driverClassName=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/student?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT jdbc.username=root jdbc.password= ############ BasicDataSource的池配置屬性 jdbc.initialSize=5 jdbc.maxActive=10
2.完成資料庫、資料來源以及bean的裝配
<!-- Spring內建JDBC資料來源 --> <!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/student?useUnicode=true&characterEncoding=utf8 &serverTimezone=GMT"/> <property name="username" value="root"/> <property name="password" value=""/> </bean> --> <!-- 配置jdbc.properties路徑 --> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties"/> </bean> <!-- 使用DBCP資料來源連線池 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <property name="initialSize" value="${jdbc.initialSize}"/> <property name="maxActive" value="${jdbc.maxActive}"/> </bean> <!-- 使用JDBC模板操作資料 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <constructor-arg ref="dataSource"/> </bean>
注意:配置連線資料庫的引數變數時,不能只寫url,username等,應為xml中使用${username}獲得的是計算機賬號的名稱,要加以區分
3.實現StudentDao方法
這一部分說白了就是編寫增刪改查的SQL語句,程式碼如下:
package example.dao; import example.entity.Student; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Repository; import java.sql.ResultSet; import java.sql.SQLException; @Repository public class StudentDaoImpl implements StudentDao { private JdbcTemplate jdbcTemplate; @Autowired public StudentDaoImpl(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } private static final String INSERT_STUDENT = "insert into student (student_id, student_name, password)" + "values (?, ?, ?)"; private static final String QUERY_STUDENT = "select student_id, student_name, password from student where student_id = ?"; private static final String UPDATE_STUDENT = "update student set student_name = ? where student_id = ?"; private static final String DELETE_STUDENT = "delete from student where student_id = ?"; @Override public void create(Student student) { jdbcTemplate.update(INSERT_STUDENT, student.getStudentId(), student.getUsername(), student.getPassword()); } @Override public Student readById(String studentId) { return jdbcTemplate.queryForObject( QUERY_STUDENT, new StudentRowMapper(), studentId ); } @Override public void updateName(String studentId, String newUsername) { jdbcTemplate.update(UPDATE_STUDENT, newUsername, studentId); } @Override public void deleteById(String studentId) { jdbcTemplate.update(DELETE_STUDENT, studentId); } private static final class StudentRowMapper implements RowMapper<Student> { @Override public Student mapRow(ResultSet resultSet, int i) throws SQLException { return new Student( resultSet.getString("student_id"), resultSet.getString("student_name"), resultSet.getString("password") ); } } }
使用@Repository註解使得Spring能夠自動生成StudentDao的bean,同時注入JDBCTemplatebean用於資料庫sql的操作,
需要注意的是,呼叫JdbcTemplate.queryForObject()方法時,需要一個RowMapper物件用於存放查詢的Student物件,因此,
在程式碼最後我們定義了一個內部類實現了RowMapper介面,並實現了mapRow()方法用於返回一個Student的例項
以上,我們的程式碼實現就完成了。要執行web專案,我們還需要在Mysql資料庫中建立student表以及建立相關檢視
home.jsp
<%-- Created by IntelliJ IDEA. User: asus1 Date: 2019/1/6 Time: 12:06 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> Hello world! Hello SpringMVC! <div> create: <form action="http://localhost:8080/trymaven/student/create" method="post"> studentId: <input type="text" name="studentId" placeholder="studentId"/> username: <input type="text" name="username" placeholder="username"/> password: <input type="password" name="password" placeholder="password"/> <input type="submit" value="submit"/> </form> </div> <div> read: <form action="http://localhost:8080/trymaven/student/read" method="get"> studentId: <input type="text" name="studentId" placeholder="studentId"/> <input type="submit" value="submit"> </form> </div> <div> update: <form action="http://localhost:8080/trymaven/student/update" method="post"> studentId: <input type="text" name="studentId" placeholder="studentId"/> new username: <input type="text" name="newUsername" placeholder="new username"/> <input type="submit" value="submit"/> </form> </div> <div> delete: <form action="http://localhost:8080/trymaven/student/delete" method="post"> studentId: <input type="text" name="studentId" placeholder="studentId"/> <input type="submit" value="submit"/> </form> </div> </body> </html>
student.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%-- Created by IntelliJ IDEA. User: asus1 Date: 2019/1/6 Time: 19:39 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>student</title> </head> <body> <div class="studentView"> <span class="studentId"><c:out value="${student.studentId}"/></span> <span class="studentName"><c:out value="${student.username}"/></span> </div> </body> </html>
deleteSuccessfully.jsp
<%-- Created by IntelliJ IDEA. User: asus1 Date: 2019/1/6 Time: 19:45 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>deleteState</title> </head> <body> The information is deleted successfully. </body> </html>
四、執行web專案
通過Tomcat啟動專案: