SSM強(qiáng)化學(xué)習(xí):從零到部署

SSM強(qiáng)化學(xué)習(xí):從零到部署

本次是一次對(duì)SSM高級(jí)整合的練手勃蜘,主要加強(qiáng)基本使用SSM做增刪改查操作。項(xiàng)目?jī)?nèi)容是對(duì)員工數(shù)據(jù)的增刪改查扳肛。

在項(xiàng)目開(kāi)始之前先建兩張表分別為員工表Employee和部門(mén)表dept:

-- ----------------------------
-- Table structure for tbl_dept
-- ----------------------------
DROP TABLE IF EXISTS `tbl_dept`;
CREATE TABLE `tbl_dept` (
  `deot_id` int(11) NOT NULL AUTO_INCREMENT,
  `dept_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  PRIMARY KEY (`deot_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- ----------------------------
-- Table structure for tbl_emp
-- ----------------------------
DROP TABLE IF EXISTS `tbl_emp`;
CREATE TABLE `tbl_emp` (
  `emp_id` int(11) NOT NULL AUTO_INCREMENT,
  `emp_name` varchar(235) NOT NULL,
  `gender` char(1) DEFAULT NULL,
  `emil` varchar(255) DEFAULT NULL,
  `d_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`emp_id`),
  KEY `fk_emp_deptt` (`d_id`),
  CONSTRAINT `fk_emp_dept` FOREIGN KEY (`d_id`) REFERENCES `tbl_dept` (`deot_id`),
  CONSTRAINT `fk_emp_deptt` FOREIGN KEY (`d_id`) REFERENCES `tbl_dept` (`deot_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

SET FOREIGN_KEY_CHECKS = 1;

一走敌、基礎(chǔ)環(huán)境的搭建

1、創(chuàng)建一個(gè)maven工程

image.png

2池磁、引入項(xiàng)目依賴(lài)的jar包

<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>com.qroxy</groupId>
  <artifactId>ssm</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  
  <!-- 引入項(xiàng)目依賴(lài)包 -->
  <!-- springMVC -->
  <dependencies>
  <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.3.7.RELEASE</version>
</dependency>
  <!--spring-Jdbc  -->
  <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.3.7.RELEASE</version>
</dependency>
    <!-- spring 面向切面編程 -->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.3.7.RELEASE</version>
    <!--mybatis-->
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->

</dependency>
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.2</version>
</dependency>
    <!-- mybtis整合適配包 -->
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.1</version>
</dependency>
    
<!-- springTest -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>4.3.7.RELEASE</version>
    <scope>test</scope>
</dependency>

    <!--  數(shù)據(jù)庫(kù)連接池-->
    <!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
<dependency>
    <groupId>c3p0</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.1.2</version>
</dependency>
    <!-- mysql 驅(qū)動(dòng)包 -->
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.11</version>
</dependency>
<!-- web工程標(biāo)配包(jstl,servlet-api,junit) -->
<!-- https://mvnrepository.com/artifact/jstl/jstl -->
<dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <!-- scop標(biāo)簽作用:服務(wù)器已經(jīng)有 -->
    <scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

</dependency>

  </dependencies>
</project>

二、引入bootstrap前端框架

為了快速搭建前端頁(yè)面楷兽,使用了bootstrap框架地熄。在WEB-INF下新建一個(gè)static文件夾存放bootstrap和js。


image.png
image.png

三芯杀、編寫(xiě)SSM整合的關(guān)鍵配置文件

1端考、首先是web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">
    
    <!--1、啟動(dòng)Spring的容器 applicationContext.xml為spring配置文件 -->
    <!-- needed for ContextLoaderListener -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

    <!-- Bootstraps the root web application context before servlet initialization -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <!--2揭厚、springmvc的前端控制器却特,攔截所有請(qǐng)求  -->
    <!-- The front controller of this Spring Web application, responsible for handling all application requests -->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- Map all requests to the DispatcherServlet for handling -->
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    <!-- 3、字符編碼過(guò)濾器筛圆,一定要放在所有過(guò)濾器之前 -->
    <filter>
        <filter-name>CharacterEncodingFilter</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>
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <!-- 4裂明、使用Rest風(fēng)格的URI,將頁(yè)面普通的post請(qǐng)求轉(zhuǎn)為指定的delete或者put請(qǐng)求 -->
    <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>
    <filter>
        <filter-name>HttpPutFormContentFilter</filter-name>
        <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HttpPutFormContentFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    
</web-app>

需要注意的是使用rest風(fēng)格uri時(shí)需要添加一個(gè)攔截PUT的攔截器太援,具體實(shí)現(xiàn)看HttpPutFormContentFilter這個(gè)類(lèi)闽晦。

2扳碍、spring核心配置文件

該文件需放在resource下

<?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 http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<context:component-scan base-package="com.qroxy">

<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

<!-- ============Spring的配置文件,這里要配置和業(yè)務(wù)邏輯相關(guān)的bean -->
<!-- 數(shù)據(jù)源仙蛉,事務(wù)控制xxx -->
<context:property-placeholder location="classpath:dbconfig.properties"/>
<bean id="pooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="user" value="${jdbc.password}"></property>
<property name="password" value="${jdbc.user}"></property>
</bean>
<!--================== 配置和MyBatis的整合=============== -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 指定mybatis全局配置文件的位置 -->
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <property name="dataSource" ref="pooledDataSource"></property>
        <!-- 指定mybatis笋敞,mapper文件的位置 -->
        <property name="mapperLocations" value="classpath:mapper/*.xml"></property>
    </bean>
<!-- 配置掃描器,將mybatis接口的實(shí)現(xiàn)加入ioc容器中 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 掃描dao接口實(shí)現(xiàn)荠瘪,加入ioc容器中 -->
<property name="basePackage" value="com.qroxy.crud.dao"></property>

</bean>
<!--  配置一個(gè)可以批量的sqlsession-->
<bean id="SqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory" ></constructor-arg>
<constructor-arg name="executorType" value="BATCH"></constructor-arg>
</bean>
<!-- ========事務(wù)控制配置 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 控制住數(shù)據(jù)源 -->
<property name="dataSource" ref="pooledDataSource"></property>
</bean>
<!--開(kāi)啟基于注解的事務(wù)夯巷,使用xml形式的事務(wù)(主要使用配置xml方式)  -->
<aop:config>
<!-- 切入點(diǎn)表達(dá)式,雙點(diǎn)表示子包也能掃描得到,括號(hào)里面表示事務(wù)任意多 -->
        <aop:pointcut expression="execution(* com.qroxy.crud.service..*(..))" id="txPoint"/>
<!-- 配置事務(wù)增強(qiáng) -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
</aop:config>
<!-- 配置事務(wù)增強(qiáng) ,如何啟動(dòng)-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 所有方法都是事務(wù)方法 -->
<tx:method name="*"/>
<!-- 以get開(kāi)頭的所有方法 -->
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- Spring配置文件的核心點(diǎn)(數(shù)據(jù)源哀墓,與mybatis的整合趁餐,事務(wù)控制) -->
</beans>

主要是對(duì)事務(wù)和mybatis整合的配置,其中:

<!--  配置一個(gè)可以批量的sqlsession-->
<bean id="SqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory" ></constructor-arg>
<constructor-arg name="executorType" value="BATCH"></constructor-arg>
</bean>

只是用來(lái)批量生成數(shù)據(jù)的sqlseesion麸祷。
在整合完成且逆向生成文件后澎怒,測(cè)試其實(shí)現(xiàn)方式如下:

<!--省去相關(guān)注解-->
EmployeeMapper mapper=SqlSession.getMapper(EmployeeMapper.class);
    for (int i = 0; i < 1000; i++) {
        String uuid=UUID.randomUUID().toString().substring(0, 5)+""+i;
        mapper.insertSelective(new Employee(null,   uuid, "W", uuid+"@qroxy.cn", 2));
    }

3、配置mybatis文件

文件位置與spring配置文件位置一致

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    
    <typeAliases>
        <package name="com.qroxy.crud.bean"/>
    </typeAliases>
<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <!--  分頁(yè)合理化參數(shù),避免出現(xiàn)頁(yè)數(shù)為負(fù)或者超過(guò)總頁(yè)數(shù)-->
        <property name="reasonable" value="true"/>
    </plugin>
</plugins>
</configuration>

4阶牍、SpringMVC文件的配置

該文件放在WEB_IN目錄下

<?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:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- springMVC的配置文件喷面,包括網(wǎng)站跳轉(zhuǎn)邏輯的控制,配置 -->
<context:component-scan base-package="com.qroxy" use-default-filters="false">
<!-- 只掃描控制器 -->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 配置視圖解析器 方便頁(yè)面返回 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>

</bean>
<!-- 兩個(gè)標(biāo)準(zhǔn)配置 -->
<!--將springMVC不能處理的請(qǐng)求交給tomcat  -->
<mvc:default-servlet-handler/>
<!--  支持springMVC更高級(jí)的一些功能走孽,JSR303校驗(yàn)惧辈,快捷ajax,映射動(dòng)態(tài)請(qǐng)求-->
<mvc:annotation-driven/>
</beans>

以上就是對(duì)SSM的一個(gè)初步整合磕瓷,要對(duì)員工數(shù)據(jù)進(jìn)行增刪改查還得需要使用mybatis的逆向工程生成對(duì)應(yīng)的bean以 及mapper盒齿。

四、mybatis的逆向工程

可去mybatis官網(wǎng)看下相關(guān)文檔困食,根據(jù)需要配置边翁。

<?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">
        <commentGenerator>
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
        <!-- 配置數(shù)據(jù)庫(kù)連接 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
            connectionURL="jdbc:mysql://localhost:3306/ssm_crud" userId="root"
            password="123456">
        </jdbcConnection>

        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <!-- 指定javaBean生成的位置 -->
        <javaModelGenerator targetPackage="com.atguigu.crud.bean"
            targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>

        <!--指定sql映射文件生成的位置 -->
        <sqlMapGenerator targetPackage="mapper" targetProject=".\src\main\resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>

        <!-- 指定dao接口生成的位置,mapper接口 -->
        <javaClientGenerator type="XMLMAPPER"
            targetPackage="com.atguigu.crud.dao" targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>


        <!-- table指定每個(gè)表的生成策略 -->
        <table tableName="tbl_emp" domainObjectName="Employee"></table>
        <table tableName="tbl_dept" domainObjectName="Department"></table>
    </context>
</generatorConfiguration>

運(yùn)行配置文件硕盹,官方提供了java文件運(yùn)行和maven運(yùn)行兩種方式符匾,這里采用java方式,在test包下新建一個(gè)類(lèi)瘩例,點(diǎn)開(kāi)Running MyBatis Generator選項(xiàng)啊胶,選擇java運(yùn)行模版如下:

package com.atguigu.crud.test;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

public class MBGTest {

    public static void main(String[] args) throws Exception {
        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;
        File configFile = new File("mbg.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);
    }
}


右鍵運(yùn)行就會(huì)生成對(duì)于javabean和xml等文件。


image.png

五垛贤、用傳統(tǒng)的方式做一個(gè)簡(jiǎn)單的查詢(xún)

具體實(shí)現(xiàn)過(guò)程:

? 1焰坪、訪(fǎng)問(wèn)index.jsp頁(yè)面

項(xiàng)目運(yùn)行進(jìn)入首頁(yè)

? 2、index.jsp頁(yè)面發(fā)送出查詢(xún)員工列表請(qǐng)求

在inde.jsp頁(yè)面做一個(gè)跳轉(zhuǎn):

<jsp:forward page="/emps"></jsp:forward> 

? 3聘惦、EmployeeController來(lái)接受請(qǐng)求某饰,查出員工數(shù)據(jù)

簡(jiǎn)單寫(xiě)一個(gè)控制器:

@RequestMapping("/emps")
    public String getEmps(@RequestParam(value = "pn", defaultValue = "1") Integer pn,Model model){
        // 這不是一個(gè)分頁(yè)查詢(xún)
        // 引入PageHelper插件
        // 在查詢(xún)之前只需要調(diào)用,傳入頁(yè)碼以及頁(yè)碼大小
        PageHelper.startPage(pn, 10);
        // startPage后面緊跟的這個(gè)查詢(xún)就是分頁(yè)查詢(xún)
    
        List<Employee> emps = employeeService.getAll();
//      使用pageInfo包裝查詢(xún)結(jié)果,只需要把pageInfo交給頁(yè)面就行
//          封裝了詳細(xì)的分頁(yè)信息,包括查詢(xún)出來(lái)數(shù)據(jù)露乏,連續(xù)顯示的頁(yè)數(shù)譬如5
        PageInfo page = new PageInfo(emps,5);
        model.addAttribute("PageInfo",page);
        
        return "list";
    }

因?yàn)橐龇猪?yè)處理碧浊,還得引入PageHelper相關(guān)依賴(lài),并進(jìn)行配置瘟仿。
依賴(lài)

!--引入PageHelper分頁(yè)插件  -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.0.0</version>
</dependency>

并在mybatis配置文件做一個(gè)配置。(已配置)

? 4比勉、來(lái)到list.jsp頁(yè)面進(jìn)行展示

在WEB_INF下新建一個(gè)views文件再里面建一個(gè)list.jsp文件:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>員工列表</title>
<%
    pageContext.setAttribute("APP_PATH", request.getContextPath());
%>
<!-- web路徑劳较,不以/開(kāi)始的相對(duì)路徑,找資源浩聋,以當(dāng)前路徑為標(biāo)準(zhǔn)观蜗,經(jīng)常出問(wèn)題
    以/開(kāi)始的相對(duì)路徑。找資源衣洁,以服務(wù)器路徑為準(zhǔn),需要加上項(xiàng)目名
    http://localhost:3306/crud
 -->
<script src="${ APP_PATH}/static/js/jquery-1.12.4.min.js"></script>
<!-- 引入Bootstrap樣式 -->
<link
    href="${ APP_PATH}/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"
    rel="stylesheet">
<!--     引入Bootstrapjs
 -->
<script
    src="${ APP_PATH}/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
</head>
<body>
    <!--  顯示頁(yè)面-->
    <div class="container">
        <!--標(biāo)題  -->
        <div class="row">
            <div class=".col-md-12">
                <h1>SSM_CRUD</h1>
            </div>
        </div>
        <!--按鈕  -->
        <div class="row">
            <div class="col-md-2 col-md-offset-10">
                <button class="btn btn-primary btn-sm">新增</button>
                <button class="btn btn-danger btn-sm">刪除</button>
            </div>
        </div>
        <!-- 顯示數(shù)據(jù) -->
        <div class="row">
            <div class="col-md-12">
                <table class="table table-hover">
                    <tr>
                        <th>#</th>
                        <th>empName</th>
                        <th>gender</th>
                        <th>email</th>
                        <th>deptName</th>
                        <th>操作</th>
                    </tr>
                    <c:forEach items="${PageInfo.list }" var="emp">
                    
                    <tr>
                        <th>${emp.empId }</th>
                        <th>${emp.empName }</th>
                        <th>${emp.gender=="M"?"男":"女" }</th>
                        
                        <th>${emp.email }</th>
                        <th>${emp.department.deptName }</th>
                        <th>
                            <button class="btn-primary btn-sm">
                                <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>編輯
                            </button>
                            <button class="btn-danger btn-sm">
                                <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>刪除
                            </button>
                        </th>
                    </tr>
                    </c:forEach>
                    
                </table>

            </div>
        </div>
        <!-- 顯示分頁(yè)信息欄 -->
        <div class="row">
            <!-- 分頁(yè)文字信息 -->
            <div class="col-md-6">
            當(dāng)前第${PageInfo.pageNum }頁(yè),總${PageInfo.pages }頁(yè),總${PageInfo.total }記錄
            </div>
            <div class="col-md-6">
                <nav aria-label="Page navigation">
                <ul class="pagination">
                <li><a href="${APP_PATH }/emps?pn=1">首頁(yè)</a></li>
                <c:if test="${PageInfo.hasPreviousPage }">
                
                <li><a href="${ APP_PATH}/emps?pn=${PageInfo.pageNum-1}" aria-label="Previous"> <span
                            aria-hidden="true">&laquo;</span>
                    </a></li>
                </c:if>
                
                    
                    <c:forEach items="${PageInfo.navigatepageNums }" var="page_Num">
                    <c:if test="${page_Num==PageInfo.pageNum }">
                    <li class="active"><a href="#">${page_Num}</a></li>
                    </c:if>
                    <c:if test="${page_Num!=PageInfo.pageNum }">
                    <li><a href="${ APP_PATH}/emps?pn=${page_Num}">${page_Num}</a></li>
                    </c:if>
                    </c:forEach>
                    
                    <c:if test="${PageInfo.hasNextPage }">
                    <li><a href="${ APP_PATH}/emps?pn=${PageInfo.pageNum+1}" aria-label="Next"> <span
                            aria-hidden="true">&raquo;</span>
                    </a></li>
                    </c:if>
                    
                    <li><a href="${APP_PATH }/emps?pn=${PageInfo.pages}">末頁(yè)</a></li>
                </ul>
                </nav>
            </div>
        </div>
    </div>
</body>
</html>

? 5墓捻、pageHelper分頁(yè)插件完成分頁(yè)查詢(xún)功能

image.png

六、利用ajax來(lái)請(qǐng)求數(shù)據(jù)渲染前端頁(yè)面

前面使用傳統(tǒng)的渲染頁(yè)面坊夫,不但效率差砖第,還對(duì)服務(wù)器性能有影響,并且這種方式只能在瀏覽器實(shí)現(xiàn)环凿,終端耦合高梧兼,而使用ajax來(lái)請(qǐng)求數(shù)據(jù)的話(huà)就相對(duì)來(lái)說(shuō)沒(méi)有以上的缺點(diǎn)或者影響更小。
主要實(shí)現(xiàn)過(guò)程如下(以查詢(xún)員工為例):

?1智听、index.jsp頁(yè)面直接發(fā)送ajax請(qǐng)求進(jìn)行員工分頁(yè)數(shù)據(jù)的查詢(xún)

$(function() {
            //去首頁(yè)
            to_page(1)
        });
        //抽離方法
        function to_page(pn) {
            $.ajax({
                url : "${APP_PATH}/emps",
                data : "pn=" + pn,
                type : "GET",
                success : function(result) {
                    //console.log(result)
                    //1羽杰、解析并顯示員工數(shù)據(jù)
                    build_emps_table(result);
                    //2、解析并顯示分頁(yè)信息
                    build_page_info(result);
                    //3到推、解析分頁(yè)條信息
                    build_page_nav(result);
                }
            });
        }
        function build_emps_table(result) {
            //請(qǐng)空表格
            $("#emps_tables tbody").empty();
            var emps = result.extend.PageInfo.list;
            $.each(emps, function(index, item) {
                var empIdTd = $("<td></td>").append(item.empId);
                var empIdNameTd = $("<td></td>").append(item.empName);
                var genderTd = $("<td></td>").append(
                        item.gender == 'M' ? "男" : "女");
                var emailTd = $("<td></td>").append(item.email);
                var departmentTd = $("<td></td>").append(
                        item.department.deptName);
                var editBtn = $("<button></button>").addClass(
                        "btn-primary btn-sm btn_edit").attr("id","btn_edit").append(
                        $("<span></span>").addClass(
                                "glyphicon glyphicon-pencil")).append("編輯");
                //添加一個(gè)屬性value是id值
                editBtn.attr("edit_id",item.empId);
                var deletBtn = $("<button></button>").addClass(
                        "btn-danger btn-sm").attr("id","btn_delet").append(
                        $("<span></span>")
                                .addClass("glyphicon glyphicon-trash")).append(
                        "刪除");
                deletBtn.attr("delet_id",item.empId);
                var butnTd = $("<td></td>").append(editBtn).add(deletBtn);
                /*  append方法執(zhí)行完成以后還是返回原來(lái)的元素*/
                $("<tr></tr>").append(empIdTd).append(empIdNameTd).append(
                        empIdNameTd).append(genderTd).append(emailTd)

                .append(departmentTd).append(butnTd)

                .appendTo("#emps_tables tbody");

            })
        }
        //解析顯示分頁(yè)信息
        function build_page_info(result) {
            $("#page_info").empty();
            $("#page_info").append(
                    "當(dāng)前第" + result.extend.PageInfo.pageNum + "頁(yè)考赛,總"
                            + result.extend.PageInfo.pages + "頁(yè),總"
                            + result.extend.PageInfo.total + "條記錄")
                            currentPage=result.extend.PageInfo.pageNum;
        }
        //解析顯示分條信息,點(diǎn)擊分頁(yè)有跳轉(zhuǎn)動(dòng)作

        function build_page_nav(result) {
            $("#page_nav").empty();
            //page_nav
            var ul = $("<ul></ul>").addClass("pagination");
            //構(gòu)建元素
            var firstPage = $("<li></li>").append(
                    $("<a></a>").append("首頁(yè)").attr("href", "#"));
            var prePage = $("<li></li>").append($("<a></a>").append("&laquo;"));
            if (result.extend.PageInfo.hasPreviousPage == false) {
                prePage.addClass("disabled");
                firstPage.addClass("disabled");
            } else {
                //首頁(yè)

                firstPage.click(function() {
                    to_page(1);
                });
                //點(diǎn)擊上一頁(yè)跳轉(zhuǎn)動(dòng)作
                prePage.click(function() {
                    to_page(result.extend.PageInfo.pageNum - 1);
                });

            }

            var nextPage = $("<li></li>")
                    .append($("<a></a>").append("&raquo;"));
            var lastPage = $("<li></li>").append(
                    $("<a></a>").append("末頁(yè)").attr("href", "#"));
            if (result.extend.PageInfo.hasNextPage == false) {
                nextPage.addClass("disabled");
                lastPage.addClass("disabled");
            } else {
                //點(diǎn)擊下一頁(yè)跳轉(zhuǎn)動(dòng)作
                nextPage.click(function() {
                    to_page(result.extend.PageInfo.pageNum + 1);
                });
                //末頁(yè)
                lastPage.click(function() {
                    to_page(result.extend.PageInfo.pages);
                });
            }

            ul.append(firstPage).append(prePage);
            //添加首頁(yè)和前一頁(yè)
            //1莉测,2颜骤,3,悔雹,4复哆,5添加頁(yè)碼提示
            $.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");

                }

                //點(diǎn)擊上一頁(yè)跳轉(zhuǎn)動(dòng)作

                numLi.click(function() {
                    to_page(item);
                });

                ul.append(numLi);

            });
            //全部添加完后,再添加最后一頁(yè)和下一頁(yè)提示
            ul.append(nextPage).append(lastPage);
            var navEle = $("<nav></nav>").append(ul);
            navEle.appendTo("#page_nav");
            numLi.click(function() {
                to_page(item);
            });
        }
        function reset_form(ele){
            $(ele)[0].reset();
            //清空表單樣式
            $(ele).find("*").removeClass("has-error has-success");
            $(ele).find(".help-block").text("");
        }

? 2腌零、服務(wù)器將查出的數(shù)據(jù)梯找,以json字符串的形式返回給瀏覽器

要服務(wù)器能json的方式返回?cái)?shù)據(jù),還要引入json包

<!-- 引入json包 -->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.8.8</version>
</dependency>

java實(shí)現(xiàn):

/*
     * 用responseBody生成json數(shù)據(jù)益涧,必須先導(dǎo)入jackson包
     */
    @RequestMapping("/emps")
    @ResponseBody
    public Msg getEmpWithJson(@RequestParam(value = "pn", defaultValue = "1") Integer pn) {
        // 這不是一個(gè)分頁(yè)查詢(xún)
                // 引入PageHelper插件
                // 在查詢(xún)之前只需要調(diào)用,傳入頁(yè)碼以及頁(yè)碼大小
                PageHelper.startPage(pn, 10);
                // startPage后面緊跟的這個(gè)查詢(xún)就是分頁(yè)查詢(xún)
            
                List<Employee> emps = employeeService.getAll();
//              使用pageInfo包裝查詢(xún)結(jié)果锈锤,只需要把pageInfo交給頁(yè)面就行
//                  封裝了詳細(xì)的分頁(yè)信息,包括查詢(xún)出來(lái)數(shù)據(jù),連續(xù)顯示的頁(yè)數(shù)譬如5
                PageInfo page = new PageInfo(emps,5);
                return Msg.success().add("PageInfo", page);
    }

? 3久免、瀏覽器收到j(luò)s字符串浅辙。可以使用js對(duì)json進(jìn)行解析阎姥,使用js通過(guò) dom增刪改改變頁(yè)面记舆。

進(jìn)而實(shí)現(xiàn)了實(shí)現(xiàn)客戶(hù)端的無(wú)關(guān)性。

七呼巴、數(shù)據(jù)校驗(yàn)

在添加員工和修改員工時(shí)為了更好的交互體驗(yàn)和防止數(shù)據(jù)臃腫泽腮,必須對(duì)提交數(shù)據(jù)進(jìn)行校驗(yàn)。

1衣赶、前端校驗(yàn)

利用正則表達(dá)式對(duì)提交數(shù)據(jù)校驗(yàn)诊赊,方法如下:

function validate_add_from() {
            //1、拿到要校驗(yàn)的數(shù)據(jù)
            var empName = $("#empName_add").val();
            //數(shù)字字母中文
            var regName = /(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;

            //校驗(yàn)郵箱信息
            var email = $("#email").val();
            var regemail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;

            if (regName.test(empName) == false) {
                show_validate_msg("#empName_add", "error", "用戶(hù)名不規(guī)則8椤碧磅!");
                return false;
            } else {
                show_validate_msg("#empName_add", "success", "");
            }

            if (regemail.test(email) == false) {
                show_validate_msg("#email", "error", "郵箱格式不對(duì)!遵馆!");

                return false;
            } else {
                show_validate_msg("#email", "success", "");

            }
            return true;
        }

2鲸郊、后端校驗(yàn)

當(dāng)有人改了前端判斷依據(jù)時(shí),前端校驗(yàn)規(guī)則就會(huì)失效团搞,此時(shí)就需要后端對(duì)數(shù)據(jù)重復(fù)校驗(yàn)严望。
引入校驗(yàn)依賴(lài)

<!--  支持?jǐn)?shù)據(jù)校驗(yàn)JSR303,tomcat7以上的服務(wù)器直接導(dǎo)入逻恐,以下的服務(wù)器:el表達(dá)式不是新標(biāo)準(zhǔn)lib中替換新標(biāo)準(zhǔn)-->
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.0.7.Final</version>
</dependency>

并在SpringMVC配置文件做好相關(guān)配置像吻。
在Employee.java對(duì)相關(guān)需要校驗(yàn)的字段進(jìn)行注解校驗(yàn):

....
//  JSR數(shù)據(jù)校驗(yàn)
  @Pattern(regexp="^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$",message="郵箱格式不對(duì)")
  private String email;
  
    @Pattern(regexp="(^[a-zA-Z0-9_-]{6,16}$)|(^[\\u2E80-\\u9FFF]{2,5})",message="用戶(hù)名不規(guī)則")
    private String empName;
    ...

在控制器中寫(xiě)一個(gè)校驗(yàn)接口:

/*
     * 校驗(yàn)用戶(hù)名是否可用
     */
    @RequestMapping("/checkuser")
    @ResponseBody
    
    public Msg checkUser(@RequestParam("empName")String empName) {
        //先判斷用戶(hù)名是否合法的
        String regx="(^[a-zA-Z0-9_-]{6,16}$)|(^[\\u2E80-\\u9FFF]{2,5})";
        if (!empName.matches(regx)) {
            return Msg.fail().add("va_msg", "用戶(hù)名不規(guī)則");
        }
        boolean b= employeeService.checkUser(empName);
        if (b) {
            return Msg.success();
        }else {
            return Msg.fail().add("va_msg", "用戶(hù)名不可用");
        }
    }

其對(duì)應(yīng)的service實(shí)現(xiàn)類(lèi)中的方法:

public Boolean checkUser(String empName) {
        EmployeeExample example = new EmployeeExample();
        Criteria criteria = example.createCriteria();
        criteria.andEmpNameEqualTo(empName);
        long count = mapper.countByExample(example);
        if (count == 0) {
            return true;
        } else {
            return false;
        }
    }

八、生成war部署Tomcat

完成項(xiàng)目后复隆,就是部署項(xiàng)目項(xiàng)目拨匆。操作如下:


image.png

成功后就會(huì)看到war包:


image.png

復(fù)雜粘貼到tomcat的webapp目錄下啟動(dòng),就會(huì)生成對(duì)應(yīng)的目錄挽拂。
image.png
image.png

打開(kāi)目錄會(huì)發(fā)現(xiàn)maven已經(jīng)把所有需要的依賴(lài)都打包好了惭每。


image.png

然后也可以訪(fǎng)問(wèn)到該服務(wù)器,此時(shí)已經(jīng)不是鏡像服務(wù)器了亏栈,而是實(shí)際服務(wù)器了台腥。


image.png

image.png

九、總結(jié)

本次學(xué)習(xí)過(guò)程讓我覺(jué)得對(duì)Spring實(shí)現(xiàn)原理的理解非常重要绒北,SSM最讓新手畏懼就是其繁瑣的配置黎侈,在本次學(xué)習(xí)過(guò)程出現(xiàn)錯(cuò)誤最多都是跟配置文件配置有關(guān),且如果對(duì)SSM它的實(shí)現(xiàn)過(guò)程沒(méi)有一個(gè)比較清晰的理解的話(huà)闷游,即使出現(xiàn)錯(cuò)誤也不能找出原因峻汉。做數(shù)據(jù)處理的時(shí)候也經(jīng)常出錯(cuò)贴汪,這個(gè)原因是因?yàn)閷?duì)jquery還不夠熟悉,因此接下來(lái)對(duì)juquery和javascript的學(xué)習(xí)也是尤為重要休吠。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末扳埂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子瘤礁,更是在濱河造成了極大的恐慌阳懂,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蔚携,死亡現(xiàn)場(chǎng)離奇詭異希太,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)酝蜒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)矾湃,“玉大人亡脑,你說(shuō)我怎么就攤上這事⊙荆” “怎么了霉咨?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)拍屑。 經(jīng)常有香客問(wèn)我途戒,道長(zhǎng),這世上最難降的妖魔是什么僵驰? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任喷斋,我火速辦了婚禮,結(jié)果婚禮上蒜茴,老公的妹妹穿的比我還像新娘星爪。我一直安慰自己,他們只是感情好粉私,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布顽腾。 她就那樣靜靜地躺著,像睡著了一般诺核。 火紅的嫁衣襯著肌膚如雪抄肖。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,462評(píng)論 1 302
  • 那天窖杀,我揣著相機(jī)與錄音漓摩,去河邊找鬼。 笑死陈瘦,一個(gè)胖子當(dāng)著我的面吹牛幌甘,可吹牛的內(nèi)容都是我干的潮售。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼做裙!你這毒婦竟也來(lái)了爽锥?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤肮帐,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后边器,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體训枢,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年忘巧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了恒界。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡砚嘴,死狀恐怖十酣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情际长,我是刑警寧澤耸采,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站工育,受9級(jí)特大地震影響虾宇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜如绸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一嘱朽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧竭沫,春花似錦燥翅、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至谎势,卻和暖如春凛膏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背脏榆。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工猖毫, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人须喂。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓吁断,卻偏偏與公主長(zhǎng)得像趁蕊,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子仔役,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 對(duì)于java中的思考的方向掷伙,1必須要看前端的頁(yè)面,對(duì)于前端的頁(yè)面基本的邏輯又兵,如果能理解最好任柜,不理解也要知道幾點(diǎn)。 ...
    神尤魯?shù)婪?/span>閱讀 814評(píng)論 0 0
  • 孩子為什么不想學(xué)宅粥? 今天上午,一位正在生氣中的母親电谣,向老師訴說(shuō)孩子的缺點(diǎn)粹胯,其中有一條就是:好好的漫畫(huà)課,說(shuō)不上就不...
    陳怡龍老師閱讀 352評(píng)論 0 0
  • 不摔跤永遠(yuǎn)不知道哪里的路最平坦
    撇捺人生Q閱讀 76評(píng)論 0 0
  • 可能時(shí)間最偉大的功能是磨光一個(gè)人的鋒芒况鸣,使想要的更加清晰牢贸,靈魂深處有一個(gè)真實(shí)的自己。 歲月總有不動(dòng)聲色的力量镐捧,可能...
    祁子聿閱讀 2,113評(píng)論 0 0
  • 青山隱隱潜索,流水潺潺, 夕去故人懂酱,已忘當(dāng)年竹习。 五年歸來(lái),樓宇成座列牺, 綠茵如聚整陌,生機(jī)盎然。 踏步漫行瞎领,高歌引路泌辫, 攜手...
    相守歸一閱讀 347評(píng)論 0 1