1, Create a maven project
2, Introduce the jar package that the project depends on [new knowledge mybatis reverse engineering, spring unit test]
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>SSM-CRUDdemo</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <!-- - - - - - - - - - - - - - - - - - Spring relevant jar package- - - - - - - - - - - - - - - - - - - - - - - - - - --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.5</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.5</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency> <!-- - - - - - - - - - - - - - - - - - Mybatis relevant jar package- - - - - - - - - - - - - - - - - - - - - - - - - - --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.2</version> </dependency> <!-- - - - - - - - - - - - - - - - - - Database related jar package- - - - - - - - - - - - - - - - - - - - - - - - - - --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!-- c3p0 Connection pool--> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency> <!-- druid Connection pool--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.3</version> </dependency> <!-- - - - - - - - - - - - - - - - - - Servlet-JSP relevant jar package- - - - - - - - - - - - - - - - - - - - - - - - - - --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.3</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- - - - - - - - - - - - - - - - - - Other related jar package- - - - - - - - - - - - - - - - - - - - - - - - - - --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> <scope>provided</scope> </dependency> <!-- json--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.1</version> </dependency> <!-- mybatis Reverse engineering dependency --> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.7</version> </dependency> <!-- spring Unit test module--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.3.5</version> <scope>test</scope> </dependency> <!-- Paging plug-in--> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.2.0</version> </dependency> <!-- JSR303 check--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.13.Final</version> </dependency> </dependencies> <!-- stay build Medium configuration resources , To prevent the failure of resource export--> <build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> </resource> </resources> </build> </project>
3, Build database environment, establish basic structure and configuration framework!
1. Build database environment
2. Establish the basic structure and configuration framework!
4, Consolidation profile
4.1. Integrate configuration files before reverse engineering without mybatis
4.2. Integrate configuration files after reverse engineering with mybatis
mybatis reverse engineering
A major feature of mybatis is that programmers need to write SQL by themselves. If there are too many tables, it will inevitably be very troublesome. Therefore, mybatis officially provides a reverse engineering, which can automatically generate the code required for mybatis execution for a single table (including pojo class, mapper.xml mapping file and Mapper interface). Generally, in practical development, the common way of reverse engineering is to generate code through the table of the database.
4.2.1. Create the configuration file generatorconfig. Required for reverse engineering of mybatis xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <context id="DB2Tables" targetRuntime="MyBatis3"> <!-- Remove generated annotations --> <commentGenerator> <property name="suppressAllComments" value="true"/> </commentGenerator> <!-- Database connection configuration --> <!-- be careful xml Not supported in&,use&replace --> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/ssm_crud?useUnicode=true&characterEncoding=utf8&useSSL=false" userId="root" password="xbh123"> </jdbcConnection> <!-- handle NUMERIC and DECIMAL Type of policy --> <javaTypeResolver> <property name="forceBigDecimals" value="false" /> </javaTypeResolver> <!-- to configure pojo Generated location --> <javaModelGenerator targetPackage="com.xbh.pojo" targetProject=".\src\main\java"> <property name="enableSubPackages" value="true" /> <property name="trimStrings" value="true" /> </javaModelGenerator> <!-- to configure sql Generation location of mapping file --> <sqlMapGenerator targetPackage="com.xbh.dao" targetProject=".\src\main\java"> <property name="enableSubPackages" value="true" /> <property name="trimStrings" value="true" /> </sqlMapGenerator> <!-- to configure dao Generation location of interface --> <javaClientGenerator type="XMLMAPPER" targetPackage="com.xbh.dao" targetProject=".\src\main\java"> <property name="enableSubPackages" value="true" /> <property name="trimStrings" value="true" /> </javaClientGenerator> <!-- Specifies the data table on which the reverse is based --> <table tableName="tbl_emp" domainObjectName="Employee"></table> <table tableName="tbl_dept" domainObjectName="Department"></table> </context> </generatorConfiguration>
Note: in this configuration file, the position of each element label is required. If the position is wrong, an error will be reported
4.2.2 generating program
public class GBKtest { public static void main(String[] args) throws Exception { List<String> warnings = new ArrayList<String>(); boolean overwrite = true; File configFile = new File("D:\\workspace_idea\\SSM-CRUDdemo\\src\\main\\resources\\generatorConfig.xml"); ConfigurationParser cp = new ConfigurationParser(warnings); Configuration config = cp.parseConfiguration(configFile); DefaultShellCallback callback = new DefaultShellCallback(overwrite); MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings); myBatisGenerator.generate(null); System.out.println("Generated successfully!"); } }
4.2.3. Generate results
4.2.4 advantages and disadvantages of reverse engineering
- Advantages: it helps us automatically generate Java code and greatly speeds up our development efficiency.
- Disadvantages: the generated files are too redundant and there is too much unnecessary code. In particular, there are too many configuration contents in the sql mapping file. For the dao layer, the methods provided are relatively limited and need to be extended by itself.
4.2.4. Spring integrates relevant configuration files of Mybatis; spring-dao.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1,Associated database profile--> <context:property-placeholder location="classpath:database.properties"/> <!-- 3,Database connection pool--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!-- Configure connection pool properties --> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ssm_crud?useSSL=true&useUnicode=true&characterEncoding=utf8"/> <property name="user" value="root"/> <property name="password" value="xbh123"/> <!-- c3p0 Private properties of connection pool --> <property name="maxPoolSize" value="30"/> <property name="minPoolSize" value="10"/> <!-- Not automatically after closing the connection commit --> <property name="autoCommitOnClose" value="false"/> <!-- Get connection timeout --> <property name="checkoutTimeout" value="10000"/> <!-- Number of retries when getting connection failed --> <property name="acquireRetryAttempts" value="2"/> </bean> <!-- 3,SqlSessionFactory--> <!-- 3.to configure SqlSessionFactory object --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- Inject database connection pool --> <property name="dataSource" ref="dataSource"/> <!-- to configure MyBatis Global profile:mybatis-config.xml --> <property name="configLocation" value="classpath:Mybatis-config.xml"/> </bean> <!-- Configure a batch execution sqlSession--> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/> <constructor-arg name="executorType" value="BATCH"/> </bean> <!-- 4.Configure scan Dao Interface package, dynamic implementation Dao Interface injection into spring In container --> <!--Explanation: https://www.cnblogs.com/jpfss/p/7799806.html--> <!-- Mybatis MapperScannerConfigurer Automatic scanning will Mapper Interface generation agent injection Spring, here mybatis-config.xml Inside<mappers><mappers/>If no configuration is required, it will be automatically scanned spring in--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- injection sqlSessionFactory --> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <!-- Given the need to scan Dao Interface package --> <property name="basePackage" value="com.xbh.dao"/> </bean> </beans>
4.2.5 Spring integration service layer -- Spring service xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:annotation-config/> <!-- 1,scanning service Package under--> <context:component-scan base-package="com.xbh.service"/> <!-- 2,Inject all our business classes into spring,It can be implemented through configuration or annotation--> <!-- <bean id="bookServiceImpl" class="com.xbh.service.BookServiceImpl">--> <!-- <property name="bookMapper" ref="bookMapper"/>--> <!-- </bean>--> <!-- 3,Configure transaction manager--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- Inject database connection pool --> <property name="dataSource" ref="dataSource" /> </bean> <!-- 4,aop Transaction support--> <!-- combination aop Implement transaction weaving--> <tx:advice id="txAdvice" transaction-manager="transactionManager" > <!-- Which methods are configured with transactions--> <tx:attributes> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!-- Configure transaction entry--> <aop:config> <aop:pointcut id="txPointCut" expression="execution(* com.xbh.dao.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/> </aop:config> </beans>
4.2.6. Add web support and write web xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--DispatcherServlet--> <servlet> <servlet-name>DispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <!--Be careful:What we load here is the total configuration file, which was damaged here before!--> <param-value>classpath:applicationContext.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!--encodingFilter--> <filter> <filter-name>encodingFilter</filter-name> <filter-class> org.springframework.web.filter.CharacterEncodingFilter </filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- use Rest Stylized URL--> <filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!--Session Expiration time--> <session-config> <session-timeout>15</session-timeout> </session-config> </web-app>
4.2.7. Spring integrates the controller layer and writes spring MVC xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- to configure SpringMVC --> <!-- 1.open SpringMVC Annotation driven --> <mvc:annotation-driven /> <!-- 2.Static resource default servlet to configure--> <mvc:default-servlet-handler/> <!-- 3.to configure jsp display ViewResolver view resolver --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="prefix" value="/WEB-INF/" /> <property name="suffix" value=".jsp" /> </bean> <!-- 4.scanning web dependent bean --> <context:component-scan base-package="com.xbh.controller" /> </beans>
5, Test dao layer
5.1. Using traditional unit test
ApplicationContext Context = new ClassPathXmlApplicationContext("applicationContext.xml"); DepartmentMapper bean = Context.getBean(DepartmentMapper.class);
5.1. Using spring unit test, we can automatically inject the components we need
1. Import the jar package required by SpringTest
<!-- spring Unit test module--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.3.5</version> <scope>test</scope> </dependency>
2. Using annotations
@ContextConfiguration specifies the location of the spring configuration file. locations = {"classpath:applicationContext.xml"}
@RunWith specifies which unit test to use. Spring junit 4classrunner defined in junit class
//Specify spring tester @RunWith(SpringJUnit4ClassRunner.class) //Using spring testing @ContextConfiguration(locations = {"classpath:applicationContext.xml"}) public class MapperTest { @Autowired DepartmentMapper departmentMapper; @Autowired EmployeeMapper employeeMapper; @Autowired SqlSession SqlSession; @Test public void testCrud(){ departmentMapper.insertSelective(new Department("Development Department")); departmentMapper.insertSelective(new Department("Testing department")); employeeMapper.insertSelective(new Employee(null,"Wang Qian","female","34009750@qq.com",1)); employeeMapper.insertSelective(new Employee(null,"Xu Baohua","male","34009750@qq.com",2)); // Batch operation EmployeeMapper mapper = SqlSession.getMapper(EmployeeMapper.class); for(int i=0;i<1000;i++){ String name=UUID.randomUUID().toString().substring(0,5)+i; mapper.insertSelective(new Employee(null,name,"male",name+"@qq.com",1)); } } }
Before using batch operations, you need to use spring Dao Configure a batch sqlSession that can be executed in XML
<!-- Configure a batch execution sqlSession--> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/> <constructor-arg name="executorType" value="BATCH"/> </bean>
results of enforcement
The batch operation was also successful
6, Query business
6.1. Query all books, and use PageHepler paging plug-in for paging query (use modal to return data)
- 1. Introduce PageHepler paging plug-in jar package
<!-- Paging plug-in--> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.2.0</version> </dependency>
- 2. Registering plug-ins in Mybatis
<plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"> <!-- set a property reasonable by true When, pageNum<=0 The default is the first page--> <property name="reasonable" value="true"/> </plugin> </plugins>
-
3. You only need to call before querying
-
controller
@Autowired EmployeeService employeeService; //Get all employees @RequestMapping("/emps") public String getEmps(@RequestParam(value="pn",defaultValue = "1")Integer pn, Model model){ //Introduce pagehelper paging plug-in PageHelper.startPage(pn,5); List<Employee> employeeList=employeeService.getAll(); //Wrap the query results with pageInfo PageInfo page = new PageInfo(employeeList,5); model.addAttribute("pageInfo",page); return "list"; }
PageHelper.startPage(page, rows);
PageInfo.class is a class in the plug-in, which is very convenient to call. Paging improves performance again:
//Current page private int pageNum; //Number of pages private int pageSize; //Number of current pages private int size; //Since startRow and endRow are not commonly used, here is a specific usage //You can "display a total of size data from startRow to endRow" on the page //The row number of the first element of the current page in the database private int startRow; //The row number of the last element of the current page in the database private int endRow; //Total records private long total; //PageCount private int pages; //Result set private List<T> list; //next page before private int prePage; //next page private int nextPage; //Is it the first page private boolean isFirstPage; //Is it the last page private boolean isLastPage; //Is there a previous page private boolean hasPreviousPage; //Is there a next page private boolean hasNextPage; //Navigation page number private int navigatePages; //All navigation page numbers private int[] navigatepageNums; //First page on the navigation bar private int navigateFirstPage; //Last page on the navigation bar private int navigateLastPage; public PageInfo() { this.isFirstPage = false; this.isLastPage = false; this.hasPreviousPage = false; this.hasNextPage = false; }
- 4. Testing
@RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(locations = {"classpath:applicationContext.xml"}) public class MvcTest { MockMvc mockMvc; @Autowired WebApplicationContext context; @Before public void initMokcMvc(){ mockMvc = MockMvcBuilders.webAppContextSetup(context).build(); } @Test public void testPage() throws Exception { // Get the return value of the simulation request MvcResult pn = mockMvc.perform(MockMvcRequestBuilders.get("/emps").param("pn", "1")).andReturn(); //After the request is successful, there will be pageInfo in the request domain MockHttpServletRequest request = pn.getRequest(); PageInfo pageInfo = (PageInfo)request.getAttribute("pageInfo"); System.out.println("Current page number"+pageInfo.getPageNum()); System.out.println("Total page number"+pageInfo.getPages()); System.out.println("Total records"+pageInfo.getTotal()); System.out.println("The number of pages that need to be displayed continuously on the page"); int[] navigateFirstPage = pageInfo.getNavigatepageNums(); for (int i : navigateFirstPage) { System.out.print(i); } } }
- test result
6.2. Write a list JSP page data (return data through model)
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- introduce Bootstrap --> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> <!-- jQuery (Bootstrap of JavaScript The plug-in needs to be imported jQuery) --> <script src="https://code.jquery.com/jquery.js"></script> <!-- Include all compiled plug-ins --> <script src="js/bootstrap.min.js"></script> </head> <body> <div class="container"> <div class="row"> <div class="col-md-12"> <h1>SSM-CRUD</h1> </div> </div> <div class="row"> <div class="col-md-4 col-md-offset-12"> <button class="btn btn-success" >newly added</button> <button class="btn btn-danger">delete</button> </div> </div> <div class="row"> <div class="col-md-12"> <table class="table table-hover table-striped"> <tr> <th>Employee number</th> <th>Employee name</th> <th>Employee gender</th> <th>mailbox</th> <th>Employee Department</th> <th>Operation button</th> </tr> <c:forEach items="${pageInfo.list}" var="emp"> <tr> <th>${emp.empId}</th> <th>${emp.empName}</th> <th>${emp.gender}</th> <th>${emp.email}</th> <th>${emp.department.deptName}</th> <th> <button class="btn btn-success btn-sm" > <span class="glyphicon glyphicon-pencil " aria-hidden="true"></span> edit </button> <button class="btn btn-danger btn-sm"> <span class="glyphicon glyphicon-trash" aria-hidden="true"></span> delete </button> </th> </tr> </c:forEach> </table> </div> </div> <div class="row"> <div class="col-md-6"> Current page number[ ${pageInfo.pageNum}],Altogether[ ${pageInfo.pages}]Page, total[ ${pageInfo.total}]Records </div> <div class="col-md-6"> <ul class="pagination"> <li ><a href="${pageContext.request.contextPath}/emps?pn=1">home page</a></li> <c:if test="${pageInfo.hasPreviousPage}"> <li><a href="${pageContext.request.contextPath}/emps?pn=${pageInfo.pageNum-1}">«</a></li> </c:if> <c:forEach items="${pageInfo.navigatepageNums}" var="pageNum"> <c:if test="${pageNum==pageInfo.pageNum}"> <li class="active"><a href="#">${pageNum}</a></li> </c:if> <c:if test="${pageNum!=pageInfo.pageNum}"> <li><a href="${pageContext.request.contextPath}/emps?pn=${pageNum}">${pageNum}</a></li> </c:if> </c:forEach> <c:if test="${pageInfo.hasNextPage}"> <li><a href="${pageContext.request.contextPath}/emps?pn=${pageInfo.pageNum+1}">»</a></li> </c:if> <li><a href="${pageContext.request.contextPath}/emps?pn=${pageInfo.pages}">Last </a></li> </ul> </div> </div> </div> </body> </html>
6.3. Transform the paging query with Ajax and return the data in the form of json string
- Application scenarios of Ajax
1. Page pull to load more data
2. No refresh paging for list data
3. Form item out of focus data validation
4. Search box prompt text drop-down list
- controller
@Autowired EmployeeService employeeService; //Return data in the form of json string @RequestMapping("/emps") @ResponseBody public PageInfo getEmpsWithJson(@RequestParam(value="pn",defaultValue = "1")Integer pn){ //Introduce pagehelper paging plug-in //Before the query is called, the default value of the incoming pn is 1, pageSize is 5, meaning first pages, and 5 pages per page. PageHelper.startPage(pn,5); List<Employee> employeeList=employeeService.getAll(); //Using PageInfo to wrap the query results, you only need to give PageInfo to the page. //It encapsulates the detailed paging information, including the data userList we query, and the number of pages passed into the continuous display 5 PageInfo page = new PageInfo(employeeList,5); return page; }
- json string returned to the client
- Build a general object to facilitate general operation
@Data @AllArgsConstructor @NoArgsConstructor public class Msg { //Status code private int code; //Prompt information private String msg; //Data returned by the user to the browser private Map<String,Object> extend=new HashMap<>(); public static Msg success(){ Msg result=new Msg(); result.setCode(100); result.setMsg("Successful processing"); return result; } public static Msg fail(){ Msg result=new Msg(); result.setCode(200); result.setMsg("Processing failed"); return result; } public Msg add(String key, Object value){ this.getExtend().put(key,value); return this; } }
- Modify controller
@Autowired EmployeeService employeeService; //Return data in the form of json string @RequestMapping("/emps") @ResponseBody public Msg getEmpsWithJson(@RequestParam(value="pn",defaultValue = "1")Integer pn){ //Introduce pagehelper paging plug-in //Before the query is called, the default value of the incoming pn is 1, pageSize is 5, meaning first pages, and 5 pages per page. PageHelper.startPage(pn,5); List<Employee> employeeList=employeeService.getAll(); //Using PageInfo to wrap the query results, you only need to give PageInfo to the page. //It encapsulates the detailed paging information, including the data userList we query, and the number of pages passed into the continuous display 5 PageInfo page = new PageInfo(employeeList,5); return Msg.success().add("pageInfo",page); }
- result
6.3.1. In index JSP uses Ajax to parse json strings and complete related businesses
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- introduce Bootstrap --> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> <!-- jQuery (Bootstrap of JavaScript The plug-in needs to be imported jQuery) --> <script src="https://code.jquery.com/jquery.js"></script> <!-- Include all compiled plug-ins --> <script src="js/bootstrap.min.js"></script> </head> <body> <div class="container"> <div class="row"> <div class="col-md-12"> <h1>SSM-CRUD</h1> </div> </div> <div class="row"> <div class="col-md-4 col-md-offset-12"> <button class="btn btn-success" >newly added</button> <button class="btn btn-danger">delete</button> </div> </div> <div class="row"> <div class="col-md-12"> <table class="table table-hover table-striped" id="emps_table"> <thead> <tr> <th>Employee number</th> <th>Employee name</th> <th>Employee gender</th> <th>mailbox</th> <th>Employee Department</th> <th>Operation button</th> </tr> </thead> <tbody > </tbody> </table> </div> </div> <div class="row"> <div class="col-md-6" id="page_info_area"> </div> <div class="col-md-6" id="page_nav_area"> </div> </div> <script type="text/javascript"> $(function () { // After the page is loaded, send an Ajax request directly to the paging data to_page(1); }); //Query method function to_page(pn) { $.ajax({ url:"${pageContext.request.contextPath}/emps",//Requested address data:"pn="+pn,//Requested data type:"GET",//Type of request success:function (result) { // console.log(result) //1. Parse and display employee data build_emps_table(result); //2. Parse and display paging information build_page_info(result); //3. Parse and display paging bar data source build_page_nav(result); } }); } //Parse and display employee data function build_emps_table(result){ //Empty table $("#emps_table tbody").empty(); var emps=result.extend.pageInfo.list; $.each(emps,function (index,item) { var empIdTd=$("<td></td>").append(item.empId); var empNameTd=$("<td></td>").append(item.empName); var genderTd=$("<td></td>").append(item.gender); var emailTd=$("<td></td>").append(item.email); var deptNameTd=$("<td></td>").append(item.department.deptName); //btn button var editBtn=$("<button></button>").addClass("btn btn-success btn-sm").append($("<span></span>").addClass("glyphicon glyphicon-pencil")).append("edit"); var delBtn=$("<button></button>").addClass("btn btn-danger btn-sm").append($("<span></span>").addClass("glyphicon glyphicon-trash")).append("delete"); var btnTd=$("<td></td>").append(editBtn).append(delBtn); $("<tr></tr>").append(empIdTd).append(empNameTd).append(genderTd).append(emailTd).append(deptNameTd).append(btnTd).appendTo($("#emps_table tbody")); }); } //Parsing and displaying paging information function build_page_info(result){ $("#page_info_area").empty(); $("#page_info_area").append(" current page number ["+ result.extend.pageInfo.pageNum +"], total ["+ result.extend.pageInfo.pages +"] pages, total ["+ result.extend.pageInfo.total +"] records "); } //Parse and display paging information function build_page_nav(result){ $("#page_nav_area").empty(); var ul=$("<ul></ul>").addClass("pagination"); //First li var firstPageLi=$("<li></li>").append($("<a></a>").append("home page").attr("href","#")); var prePageLi=$("<li></li>").append($("<a></a>").append("«")); //Judge whether it is the first page at this time. If so, the function of switching page number forward at this time cannot be used if(result.extend.pageInfo.hasPreviousPage==false){ firstPageLi.addClass("disabled"); prePageLi.addClass("disabled"); }else{ //Bind click event firstPageLi.click(function () { to_page(1); }); prePageLi.click(function () { to_page(result.extend.pageInfo.pageNum-1) }); } var nextPageLi=$("<li></li>").append($("<a></a>").append("»")); var lastPageLi=$("<li></li>").append($("<a></a>").append("Last ").attr("href","#")); //Judge whether it is the last page at this time. If so, the function of switching page number forward at this time cannot be used if(result.extend.pageInfo.hasNextPage==false){ nextPageLi.addClass("disabled"); lastPageLi.addClass("disabled"); }else{ //Add click events to the next and last pages nextPageLi.click(function () { to_page(result.extend.pageInfo.pageNum+1) }); lastPageLi.click(function () { to_page(result.extend.pageInfo.pages); }); } ul.append(firstPageLi).append(prePageLi); //Traverse page number $.each(result.extend.pageInfo.navigatepageNums,function (index,item) { var numLi=$("<li></li>").append($("<a></a>").append(item)); if(result.extend.pageInfo.pageNum==item){ numLi.addClass("active"); } numLi.click(function () { to_page(item); }); ul.append(numLi); }); ul.append(nextPageLi).append(lastPageLi); var navEle=$("<nav></nav>").append(ul); navEle.appendTo($("#page_nav_area")); } </script> </div> </body> </html>
6.3.2 problems encountered
- Solve problem 1 (the previous data does not disappear after clicking)
- Solution (clear the previous data before each query)
$("#emps_table tbody").empty(); $("#page_info_area").empty(); $("#page_nav_area").empty();
Since the previous data always exists because the data is attached every time it is obtained, the previous data should be cleared
- Solve problem 2 (when the current page number is the first or last page, click the previous or next page, the current page number still jumps, and unreasonable parameters appear)
- Solution (set through the properties of pageHelper plug-in)
<plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"> <!-- set a property reasonable by true When, pageNum<=0 The default is the first page--> <property name="reasonable" value="true"/> </plugin> </plugins>
- Solve problem 3 (the difference between Ajax query (parsing json string) and model query)
The magic of Ajax
- Using Ajax, the page will not be refreshed. AJAX is a way to update some web pages without loading the whole web page, and the model will reconstruct the page (request forwarding or request redirection)
- Customers can see the data that needs to be changed in a shorter time. The server only needs to process a single task without generating the whole page
- More processing is placed on the client side, which means that JavaScript will be used frequently for development
7, New business
- backdrop:"static" specifies a static background. When the user clicks outside the modal box, the modal box will not be closed.
7.1. Add mode box
<!-- Modal --> <div class="modal fade" id="empAddModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myModalLabel">Add employee</h4> </div> <div class="modal-body"> <form class="form-horizontal" role="form"> <div class="form-group"> <label for="empName" class="col-sm-2 control-label">name</label> <div class="col-sm-10"> <input type="text" name="empName" class="form-control" id="empName" placeholder="Please enter your name"> <span class="help-block"></span> </div> </div> <div class="form-group"> <label for="email" class="col-sm-2 control-label">mailbox</label> <div class="col-sm-10"> <input type="text" name="email" class="form-control" id="email" placeholder="xxx@qq.com"> <span class="help-block"></span> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">Gender</label> <div class="col-sm-10"> <label class="radio-inline"> <input type="radio" name="gender" id="gender1" value="male" checked>male </label> <label class="radio-inline"> <input type="radio" name="gender" id="gender2" value="female">female </label> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">department</label> <%-- Department needs dynamic query--%> <div class="col-sm-4"> <select class="form-control" name="dId" id="dept_add_select"> </select> </div> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">close</button> <button type="button" class="btn btn-primary" id="emp_save_btn">preservation</button> </div> </div> </div> </div>
7.2. Add a button binding event to the employee, and the modal box pops up
// Add a button binding event to the employee, and the modal box pops up $("#emp_add_modal_btn").click(function () { //Clear the form data (form reset). jquery has no reset method and needs to take out the dom element reset_form("#empAddModal form"); getDept(); $("#empAddModal").modal({backdrop:"static"}); }); // Form complete reset (form content, form style reset) method function reset_form(ele){ //Reset form content $(ele)[0].reset(); //Reset form style $(ele).find("*").removeClass("has-error has-success"); $(ele).find(".help-block").text(""); }
7.3. Trigger getDept() when the modal box pops up; Add the option component to the drop-down box component
function getDept(){ $.ajax({ url:"${pageContext.request.contextPath}/depts", type:"GET", success:function (result){ $("#dept_add_select").empty(); //Display department information in the drop-down list $.each(result.extend.departments,function () { var optionEle=$("<option></option>").append(this.deptName).attr("value",this.deptId); optionEle.appendTo($("#dept_add_select")); }); } }); }
7.4. Department information needs to be detected in real time. Ajax is used to initiate response, and there is no need to reconstruct the page
- The controller layer calls the service layer
@Controller public class DepartmentController { @Autowired private DepartmentService departmentService; //Return all department information @RequestMapping("/depts") @ResponseBody public Msg getDepts(){ List<Department> list=departmentService.getDepts(); return Msg.success().add("departments",list); } }
- The service layer calls the dao layer
@Service public class DepartmentService { @Autowired private DepartmentMapper departmentMapper; public List<Department> getDepts() { List<Department> departments = departmentMapper.selectByExample(null); return departments; } }
7.5 click the Save button to add the information to the database and initiate a request to verify whether the data is legal
$("#emp_save_btn").click(function () { //1, The data to be submitted needs to be verified if(!validate_add_form()){ return false; } //2, Judge the status of the Save button. If it is error, return false; if(($(this).attr("ajax-va"))=="error"){ return false; } //III //1. The form data filled in the modal box is submitted to the server for saving //2. Send Ajax request to save employee //The serialize() method in jquery can serialize table content strings for Ajax requests $.ajax({ url:"${pageContext.request.contextPath}/emp", type:"POST", data:$("#empAddModal form").serialize(), success:function (result) { //Employee preservation //1. Close modal box $("#empAddModal").modal("hide"); //2. Go to the last page and display the saved data //You can jump with the total number of records to_page(999999999); } }); });
- 7.5.1 start to check whether the input data is legal
// validate form function validate_add_form(){ //Employee name var name=$("#empName").val(); var regName=/(^[a-zA-Z0-9_-]{5,8}$)|([\u2E80-\u9FFF]{2,5})/; if(!regName.test(name)){ show_validate_msg("#empName","error "," the format of the name you entered is illegal "); return false; }else{ show_validate_msg("#empName","success",""); }; //Employee email var email=$("#email").val(); var regEmail=/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/; if(!regEmail.test(email)){ show_validate_msg("#email","error "," the email format you entered is illegal "); return false; }else{ show_validate_msg("#email","success",""); }; return true; } //Extract the public method to display the status information function show_validate_msg(ele,status,msg){ //Clears the state of the current element $(ele).parent().removeClass("has-success has-error"); if("success"==status){ $(ele).parent().addClass("has-success"); $(ele).next("span").text(msg); }else if("error"==status){ $(ele).parent().addClass("has-error"); $(ele).next("span").text(msg); } };
- 7.5.2. Ajax checks whether the user name is repeated
- The client binding changes the event function and sends an Ajax request to verify whether the user name is available
//The server verifies whether the user name is available $("#empName").change(function () { //Send an Ajax request to verify that the user name is available var empName=this.value; $.ajax({ url:"${pageContext.request.contextPath}/checkUser", data:"empName="+empName, type:"POST", success:function (result) { if(result.code==100){ //success show_validate_msg("#empName","success "," user name available "); //Give the employee button a custom attribute $("#emp_save_btn").attr("ajax-va","success"); }else{ //fail show_validate_msg("#empName","error "," user name unavailable "); //The Save button should be disabled when the user name is not available $("#emp_save_btn").attr("ajax-va","error"); } } }); });
- The server receives the request and starts processing
- The controller layer calls the service layer
/** * Verify that the user name is available * @param * @return * @author Xu Baohua * @creed: Talk is cheap,show me the code * @date 2021/5/31 9:27 */ @RequestMapping("/checkUser") @ResponseBody public Msg checkUser(@RequestParam("empName") String empName){ boolean flag=employeeService.checkUser(empName); if(flag){ //available return Msg.success(); }else{ return Msg.fail(); } }
- The service layer calls the dao layer to complete the query
/** * Verify that the employee name is available * @param empName * @return true : Indicates that the current name is available, otherwise false indicates that it is not available * @author Xu Baohua * @creed: Talk is cheap,show me the code * @date 2021/5/31 9:35 */ public boolean checkUser(String empName) { EmployeeExample employeeExample = new EmployeeExample(); //Specify query rules EmployeeExample.Criteria criteria = employeeExample.createCriteria(); criteria.andEmpNameEqualTo(empName); long count = employeeMapper.countByExample(employeeExample); return count==0; }
Problems encountered:
1. The form is repeatedly submitted (when the user submits the request, the browser will record all the information of the last request. When the user presses the function key F5, the last request recorded by the browser will be initiated), and the form style should also be cleared
Solution: when clicking the Add button, reset all the form data in the modal box
// Form complete reset (form content, form style reset) method function reset_form(ele){ //Reset form content $(ele)[0].reset(); //Reset form style $(ele).find("*").removeClass("has-error has-success"); $(ele).find(".help-block").text(""); }
2. If the user name is not available, click the Save button to not submit the form data
Solution: add a user-defined attribute to the Save button, and then judge the status of the current attribute before saving
if(($(this).attr("ajax-va"))=="error"){ return false; }
3. If the background verification passes, the user name is prompted to be available, but the format of the user name verified by the client is incorrect, and the prompt contents of the front and back platforms are inconsistent, which has a certain impact on the beauty of the interface
Solution: regular expression judgment is also added in the background. The judgment content is consistent with that in the foreground, and the prompt information is also consistent, so that it will not affect the appearance of the interface because the prompt information content is different
4. After the background checks the data, it is found that the user name already exists. When the mailbox is entered, the foreground will check it again. At this time, it is found that the user name is legal and the verification has passed
Solution: add a user-defined attribute to the Save button, and then judge the status of the current attribute before saving
5. Foreground verification is only to increase the user's experience, but it is not safe. You can tamper with js content to realize form verification. For example, users can disable js code
When the user name is illegal, a private attribute is added to the Save button, and the data can be stored by tampering with the attribute,
- Extraction method
// Form complete reset (form content, form style reset) method function reset_form(ele){ //Reset form content $(ele)[0].reset(); //Reset form style $(ele).find("*").removeClass("has-error has-success"); $(ele).find(".help-block").text(""); }
7.6. Verification requires jquery front-end verification + Ajax user name duplicate verification + back-end verification (JSR303 verification based on spring MVC)
- JSR303 verification needs to import hibernate validator and requires Tomcat7 and above servers
<!-- JSR303 check--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.13.Final</version> </dependency>
- Mark the verification annotation on the javaBean to be verified
@Pattern(regexp = "(^[a-zA-Z0-9_-]{5,8}$)|([\\u2E80-\\u9FFF]{2,5})",message = "The format of the name you entered is illegal") private String empName; private String gender; //You can use Email annotation or customize it //@Pattern(regexp = "^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$",message =" the email format you entered is illegal ") @Email(message = "Email format error") private String email;
- Tell spring that this data needs to be verified @ Valid
@RequestMapping(value="/emp",method = RequestMethod.POST) @ResponseBody public Msg saveEmp(@Valid Employee employee, BindingResult result){ if(result.hasErrors()){ Map<String,Object> map=new HashMap<>(); //If the verification fails, a failure should be returned, and the error message of verification failure is displayed in the mode box List<FieldError> fieldErrors = result.getFieldErrors(); for (FieldError fieldError : fieldErrors) { System.out.println("Wrong field name"+fieldError.getField()); System.out.println("Wrong message"+fieldError.getDefaultMessage()); map.put(fieldError.getField(),fieldError.getDefaultMessage()); } return Msg.fail().add("errorField",map); }else{ employeeService.saveEmp(employee); return Msg.success(); } }
- The analog front-end verification fails, and the data cannot be stored at this time
$("#emp_save_btn").click(function () { //The data to be submitted needs to be verified // if(!validate_add_form()){ // return false; // } if(($(this).attr("ajax-va"))=="error"){ return false; } //Judge whether the previous Ajax user name verification is successful. If successful, continue to execute, //1. The form data filled in the modal box is submitted to the server for saving //2. Send Ajax request to save employee //The serialize() method in jquery can serialize table content strings for Ajax requests $.ajax({ url:"${pageContext.request.contextPath}/emp", type:"POST", data:$("#empAddModal form").serialize(), success:function (result) { if(result.code==100){ //Employee preservation //1. Close modal box $("#empAddModal").modal("hide"); //2. Go to the last page and display the saved data //You can jump with the total number of records to_page(999999999); }else{ //Display failure information if(undefined!=result.extend.errorField.email){ //Display mailbox error message show_validate_msg("#email","error",result.extend.errorField.email); } if(undefined!=result.extend.errorFields.empName){ //Display name error message show_validate_msg("#empName","error",result.extend.errorFields.empName); } } } }); });
7.7 the server receives the request to save information and starts processing
- The controller layer calls the service layer
/** * Save user information * @param * @return * @author Xu Baohua * @creed: Talk is cheap,show me the code * @date 2021/5/30 12:49 */ @RequestMapping(value="/emp",method = RequestMethod.POST) @ResponseBody public Msg saveEmp(Employee employee){ employeeService.saveEmp(employee); return Msg.success(); }
- The service layer calls the dao layer to finish saving
//Employee retention method public void saveEmp(Employee employee) { employeeMapper.insertSelective(employee); }
8, Modify business
8.1. Bind the click event to the Edit button, and the user modified mode box will pop up
Since data and buttons are created after an Ajax request is initiated, care should be taken when Binding click events
Solution:
1. Can be bound when creating a button
2. Bind and click the live() method to attach an event handler function to all matching elements. Even if this element is added later, it can still take effect. Since there is no live method in the new version of jQuery, you can use the on method instead
$(document).on("click",".edit_btn",function () { //Clear the form data (form complete reset (form content, form style reset)), jquery has no reset method and needs to remove the dom element reset_form("#empUpdateModal form"); getDept("#dept_update_select"); $("#empUpdateModal").modal({ backdrop:"static"}); });
- Modal box
<%--Modal box for employee modification--%> <!-- Modal --> <div class="modal fade" id="empUpdateModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myUpdateModalLabel">Employee modification</h4> </div> <div class="modal-body"> <form class="form-horizontal" role="form"> <div class="form-group"> <label for="empName" class="col-sm-2 control-label">name</label> <div class="col-sm-10 "> <p class="form-control-static" id="empName_update_static"></p> <span class="help-block"></span> </div> </div> <div class="form-group"> <label for="email" class="col-sm-2 control-label">mailbox</label> <div class="col-sm-10"> <input type="text" name="email" class="form-control" id="email_update_input" placeholder="xxx@qq.com"> <span class="help-block"></span> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">Gender</label> <div class="col-sm-10"> <label class="radio-inline"> <input type="radio" name="gender" id="gender1_update_input" value="male" checked>male </label> <label class="radio-inline"> <input type="radio" name="gender" id="gender2_update_input" value="female">female </label> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">department</label> <%-- Department needs dynamic query--%> <div class="col-sm-4"> <select class="form-control" name="dId" id="dept_update_select"> </select> </div> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">close</button> <button type="button" class="btn btn-primary" id="emp_update_btn">to update</button> </div> </div> </div> </div>
8.2. Initiate an Ajax request to get the data of the current employee to be modified
- controller layer
@RequestMapping(value = "/emp/{id}",method = RequestMethod.GET) @ResponseBody public Msg getEmp(@PathVariable("id") Integer id){ Employee employee=employeeService.getEmp(id); return Msg.success().add("emp",employee); }
- service layer
//Query employee information public Employee getEmp(Integer id) { Employee employee = employeeMapper.selectByPrimaryKey(id); return employee; }
- View display layer
$(document).on("click",".edit_btn",function () { //Clear the form data (form complete reset (form content, form style reset)), jquery has no reset method and needs to remove the dom element reset_form("#empUpdateModal form"); getDept("#dept_update_select"); //How to get the id value //You can add a custom attribute to the Edit button: editbtn attr("edit_id",item.empId); getEmp($(this).attr("edit_id")); $("#empUpdateModal").modal({ backdrop:"static"}); }); function getEmp(id){ $.ajax({ url:"${pageContext.request.contextPath}/emp/"+id, type:"GET", success:function (result) { var empData=result.extend.emp; $("#empName_update_static").text(empData.empName); $("#email_update_input").val(empData.email); $("#empUpdateModal input[name=gender]").val([empData.gender]); $("#dept_update_select").val([empData.dId]); } }) }
8.3. Initiate Ajax request to save the data of the current employee to be modified
- To use RestURl style, you need to use it on the web Configuration in XML
<!-- use Rest Stylized URL--> <filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
- controller layer
//At this time, note that the name of this id value should be the same as the id name in the bean object, otherwise it will not be modified @RequestMapping(value = "/emp/{empId}",method = RequestMethod.PUT) @ResponseBody public Msg saveEmp(Employee employee){ employeeService.updateEmp(employee); return Msg.success(); }
- service layer
//Modify employee information public void updateEmp(Employee employee) { employeeMapper.updateByPrimaryKeySelective(employee); }
- View display layer
//Click the update button to update the employee information $("#emp_update_btn").click(function () { //Verify whether the mailbox is legal var email=$("#email_update_input").val(); var regEmail=/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/; if(!regEmail.test(email)){ show_validate_msg("#email_update_input","error "," the email format you entered is illegal (66666 "); return false; }else{ show_validate_msg("#email_update_input","success",""); }; //Send Ajax request to save employee data $.ajax({ url:"${pageContext.request.contextPath}/emp/"+$(this).attr("edit_id"), type:"POST", data:$("#empUpdateModal form").serialize()+"&_method=PUT", success:function (result) { $("#empUpdateModal").modal("hide"); to_page(currentPage); } }); });
- Send POST request
If you directly send a request in the form of Ajax=PUT, there will be a problem. You will find that there is data in the request body, but the employee object cannot be encapsulated. The root cause is an error in the splicing of SQL statements
Reason: because of Tomcat
1. Tomcat encapsulates the data in the request body into a map
2,request.getParameter("empName") will take value from this map
3. When spring MVC encapsulates pojo objects, the value of each attribute in pojo is obtained by calling request getParameter()
The underlying reason is that ajax sends a PUT request, and the data in the request body passes through request Getparameter() cannot be obtained. If Tomcat finds that it is a PUT request, it will not encapsulate the data in the request body as a map
9, Delete business
9.1. Initiate ajax request to delete
- controller layer
//Delete employee @RequestMapping(value = "/emp/{id}",method = RequestMethod.DELETE) @ResponseBody public Msg deleteEmpById(@PathVariable("id") Integer id){ employeeService.deleteEmp(id); return Msg.success(); }
- service layer
public void deleteEmp(Integer id) { employeeMapper.deleteByPrimaryKey(id); }
- View display layer
$(document).on("click",".delete_btn",function () { var empName=$(this).parents("tr").find("td:eq(1)").text(); var empId=$(this).attr("del_id"); if(confirm("Confirm deletion["+empName+"]Do you?")){ //Confirm, send ajax request to delete //Add a custom attribute delbtn. For the delete button attr("del_id",item.empId); $.ajax({ url:"${pageContext.request.contextPath}/emp/"+empId, type:"DELETE", success:function (result) { to_page(currentPage); } }); } });
9.2. Improve all deletion functions
- controller layer (integration of single deletion and batch deletion)
//Delete employees in a single batch @RequestMapping(value = "/emp/{ids}",method = RequestMethod.DELETE) @ResponseBody public Msg deleteEmpById(@PathVariable("ids") String ids){ List<Integer> del_ids=new ArrayList<>(); if(ids.contains("-")){ //Batch delete String[] str_ids=ids.split("-"); //Collection of assembly IDS for (String str_id : str_ids) { del_ids.add(Integer.parseInt(str_id)); } employeeService.deleteBatch(del_ids); }else{ Integer id = Integer.parseInt(ids); employeeService.deleteEmp(id); } return Msg.success(); }
- service layer
//Batch delete public void deleteBatch(List<Integer> ids) { EmployeeExample employeeExample = new EmployeeExample(); EmployeeExample.Criteria criteria = employeeExample.createCriteria(); criteria.andEmpIdIn(ids); employeeMapper.deleteByExample(employeeExample); }
- View display layer
//Complete select all / deselect all button $("#checkAll").click(function () { //attr() gets checked is undefined //For dom native attributes, it is recommended to obtain them with the prop() method $(".check_item").prop("checked",$(this).prop("checked")); }); //Bind click events for each check box $(document).on("click",".check_item",function () { var flag=$(".check_item:checked").length==$(".check_item").length; $("#checkAll").prop("checked",flag); }); //Click delete all to delete in batch $("#emp_delete_all_btn").click(function () { var empNames=""; var del_idStr=""; $.each($(".check_item:checked"),function () { empNames+=$(this).parents("tr").find("td:eq(2)").text()+","; del_idStr+=$(this).parents("tr").find("td:eq(1)").text()+"-"; }); //Remove redundant symbols empNames=empNames.substring(0,empNames.length-1); del_idStr=del_idStr.substring(0,del_idStr.length-1); if(confirm("Are you sure you want to delete these["+empNames+"]Employees")){ //Confirm, send ajax request to delete //Add a custom attribute delbtn. For the delete button attr("del_id",item.empId); $.ajax({ url:"${pageContext.request.contextPath}/emp/"+del_idStr, type:"DELETE", success:function (result) { to_page(currentPage); } }); } });