一、项目分析

1、需求

(1)使用 ssm + vue 实现一个crud(数据库增删改查)的简单实现。
(2)前后端分离,前端页面展示+后台管理。

2、技术点

(1)基础框架: SSM(Spring,SpringMVC,Mybatis)
(2)数据库: Mysql
(3)前端: UI框架 iView + vue
(4)项目依赖管理: maven
(5)分页: pagehelper
(6)逆向工程: Mybatis Generator
(7)开发工具:IDEA + Chrome + HBuilder X

二、项目地址、截图

1、项目地址

  front:https://github.com/lyh-man/ssm_crud-front.git

  back:https://github.com/lyh-man/ssm_crud-back.git

2、项目截图

(1)初始界面(查数据)

  Step1:初始化界面(获取第一页数据)

  Step2:可以设置每页数据的条数,如下,设置 20条/页

  Step3:点击设置按钮,可以设置表格样式。

  Step4:切换页面,数据刷新(根据当前页码向后台发送请求,获取数据)

(2)修改数据

  Step1:点击编辑按钮(如下,选择第一条数据,展示所选择的数据。)

  Step2:修改数据

  Step3:修改后,展示数据

(3)删除数据

  Step1:点击删除按钮(比如第一条数据),会弹出一个提示框

  Step2:选择 Ok,删除该数据

(3)添加数据

  Step1:点击添加按钮

  Step2:填写信息

  Step3:点击确定,插入数据,并跳转到最后一页

三、后端项目环境搭建

  搭建后的整个文件结构:

1、使用IDEA创建一个maven工程。

  可以参考 https://www.cnblogs.com/l-y-h/p/11454933.html

2、引入项目依赖的jar包(配置依赖信息)。

  需要配置Spring,SpringMVC,mybatis,数据库连接池,数据库驱动包,以及其他的jar包,比如junit等。

  1. pom.xml
  2.  
  3. <?xml version="1.0" encoding="UTF-8"?>
  4.  
  5. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  6. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  7. <modelVersion>4.0.0</modelVersion>
  8.  
  9. <groupId>com.lyh</groupId>
  10. <artifactId>crud</artifactId>
  11. <version>1.0-SNAPSHOT</version>
  12. <packaging>war</packaging>
  13.  
  14. <name>crud Maven Webapp</name>
  15. <!-- FIXME change it to the project's website -->
  16. <url>http://www.example.com</url>
  17.  
  18. <properties>
  19. <jar.version>4.3.17.RELEASE</jar.version>
  20. </properties>
  21.  
  22. <dependencies>
  23. <!-- Spring WebMVC -->
  24. <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
  25. <dependency>
  26. <groupId>org.springframework</groupId>
  27. <artifactId>spring-webmvc</artifactId>
  28. <version>${jar.version}</version>
  29. </dependency>
  30.  
  31. <!-- Spring JDBC -->
  32. <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
  33. <dependency>
  34. <groupId>org.springframework</groupId>
  35. <artifactId>spring-jdbc</artifactId>
  36. <version>${jar.version}</version>
  37. </dependency>
  38.  
  39. <!-- Spring Aspects -->
  40. <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
  41. <dependency>
  42. <groupId>org.springframework</groupId>
  43. <artifactId>spring-aspects</artifactId>
  44. <version>${jar.version}</version>
  45. </dependency>
  46.  
  47. <!-- Mybatis -->
  48. <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
  49. <dependency>
  50. <groupId>org.mybatis</groupId>
  51. <artifactId>mybatis</artifactId>
  52. <version>3.4.6</version>
  53. </dependency>
  54.  
  55. <!-- spring 与 mybatis 的整合包 -->
  56. <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
  57. <dependency>
  58. <groupId>org.mybatis</groupId>
  59. <artifactId>mybatis-spring</artifactId>
  60. <version>1.3.2</version>
  61. </dependency>
  62.  
  63. <!-- 数据库连接池,c3p0 -->
  64. <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
  65. <dependency>
  66. <groupId>com.mchange</groupId>
  67. <artifactId>c3p0</artifactId>
  68. <version>0.9.5.4</version>
  69. </dependency>
  70.  
  71. <!-- mysql驱动包 -->
  72. <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
  73. <dependency>
  74. <groupId>mysql</groupId>
  75. <artifactId>mysql-connector-java</artifactId>
  76. <version>8.0.18</version>
  77. </dependency>
  78.  
  79. <!-- jstl -->
  80. <!-- https://mvnrepository.com/artifact/jstl/jstl -->
  81. <dependency>
  82. <groupId>jstl</groupId>
  83. <artifactId>jstl</artifactId>
  84. <version>1.2</version>
  85. </dependency>
  86.  
  87. <!-- servlet-api -->
  88. <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
  89. <dependency>
  90. <groupId>javax.servlet</groupId>
  91. <artifactId>javax.servlet-api</artifactId>
  92. <version>4.0.1</version>
  93. <scope>provided</scope>
  94. </dependency>
  95.  
  96. <!-- junit -->
  97. <!-- https://mvnrepository.com/artifact/junit/junit -->
  98. <dependency>
  99. <groupId>junit</groupId>
  100. <artifactId>junit</artifactId>
  101. <version>4.12</version>
  102. <scope>test</scope>
  103. </dependency>
  104.  
  105. <!-- 逆向工程所需的依赖信息 -->
  106. <!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
  107. <dependency>
  108. <groupId>org.mybatis.generator</groupId>
  109. <artifactId>mybatis-generator-core</artifactId>
  110. <version>1.3.5</version>
  111. </dependency>
  112.  
  113. <!-- Spring test -->
  114. <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
  115. <dependency>
  116. <groupId>org.springframework</groupId>
  117. <artifactId>spring-test</artifactId>
  118. <version>${jar.version}</version>
  119. <scope>test</scope>
  120. </dependency>
  121.  
  122. <!-- Json -->
  123. <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
  124. <dependency>
  125. <groupId>com.fasterxml.jackson.core</groupId>
  126. <artifactId>jackson-databind</artifactId>
  127. <version>2.10.0</version>
  128. </dependency>
  129.  
  130. <!-- pagehelper 分页插件 -->
  131. <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
  132. <dependency>
  133. <groupId>com.github.pagehelper</groupId>
  134. <artifactId>pagehelper</artifactId>
  135. <version>5.0.0</version>
  136. </dependency>
  137. </dependencies>
  138.  
  139. <build>
  140. <finalName>crud</finalName>
  141. <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
  142. <plugins>
  143. <plugin>
  144. <artifactId>maven-clean-plugin</artifactId>
  145. <version>3.1.0</version>
  146. </plugin>
  147. <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
  148. <plugin>
  149. <artifactId>maven-resources-plugin</artifactId>
  150. <version>3.0.2</version>
  151. </plugin>
  152. <plugin>
  153. <artifactId>maven-compiler-plugin</artifactId>
  154. <version>3.8.0</version>
  155. </plugin>
  156. <plugin>
  157. <artifactId>maven-surefire-plugin</artifactId>
  158. <version>2.22.1</version>
  159. </plugin>
  160. <plugin>
  161. <artifactId>maven-war-plugin</artifactId>
  162. <version>3.2.2</version>
  163. </plugin>
  164. <plugin>
  165. <artifactId>maven-install-plugin</artifactId>
  166. <version>2.5.2</version>
  167. </plugin>
  168. <plugin>
  169. <artifactId>maven-deploy-plugin</artifactId>
  170. <version>2.8.2</version>
  171. </plugin>
  172. </plugins>
  173. </pluginManagement>
  174. </build>
  175. </project>

3、配置ssm整合的文件(详细过程后续展开)。

  web.xml,spring,springmvc,mybatis。

4、官方文档:

  Spring:http://spring.io/docs

  MyBatis:http://mybatis.github.io/mybatis-3/

  分页组件的使用: https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/en/HowToUse.md

三、(3.1)SSM基本配置--配置web.xml

1、配置Spring容器

  用于获取 Spring 配置文件(applicationContext.xml) 的读取位置。
  <context-param>直接配置在web.xml的<web-app>标签中,属于上下文参数,在整个web应用中都可以使用。它是全局的,因此存放在servletContext对象中(即application对象)。通过getServletContext().getInitParameter("contextParam")的方式可以获取。

  1. 【在web.xml中配置】
  2.  
  3. <!-- step1: 配置全局的参数,启动Spring容器 -->
  4. <context-param>
  5. <param-name>contextConfigLocation</param-name>
  6. <!-- 若没有提供值,默认会去找/WEB-INF/applicationContext.xml -->
  7. <param-value>classpath:applicationContext.xml</param-value>
  8. </context-param>
  9. <listener>
  10. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  11. </listener>

2、配置SpringMVC的前端控制器

  用于拦截请求,并指定Spring MVC配置文件的读取位置。

  <init-parm>配置在<servlet>标签中,用来初始化当前的Servlet的。属于当前Servlet的配置,因此存放在servletConfig对象(servlet对象)中。

  通过getServletConfig().getInitParameter("initParam")的方式可以获取。

  1. 【在web.xml中配置】
  2.  
  3. <!-- step2: 配置SpringMVC的前端控制器,用于拦截所有的请求 -->
  4. <servlet>
  5. <servlet-name>springmvcDispatcherServlet</servlet-name>
  6. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  7.  
  8. <init-param>
  9. <param-name>contextConfigLocation</param-name>
  10. <!-- 若没有提供值,默认会去找WEB-INF/*-servlet.xml。 -->
  11. <param-value>classpath:dispatcher-servlet.xml</param-value>
  12. </init-param>
  13. <!-- 启动优先级,数值越小优先级越大 -->
  14. <load-on-startup>1</load-on-startup>
  15. </servlet>
  16. <servlet-mapping>
  17. <servlet-name>springmvcDispatcherServlet</servlet-name>
  18. <!-- 将DispatcherServlet请求映射配置为"/",则Spring MVC将捕获Web容器所有的请求,包括静态资源的请求 -->
  19. <url-pattern>/</url-pattern>
  20. </servlet-mapping>

注:

  spring框架在加载web配置文件的时候。首先加载的是context-param配置的内容,而并不会去初始化servlet。只有进行了网站的跳转,经过DispatcherServlet的时候,才会初始化servlet,从而加载init-param中的内容。

3、配置解决乱码问题的过滤器

  用于解决乱码问题。

  1. 【在web.xml中配置】
  2.  
  3. <!-- step3: characterEncodingFilter字符编码过滤器,放在所有过滤器的前面 -->
  4. <filter>
  5. <filter-name>characterEncodingFilter</filter-name>
  6. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  7. <init-param>
  8. <!--要使用的字符集,一般我们使用UTF-8(保险起见UTF-8最好)-->
  9. <param-name>encoding</param-name>
  10. <param-value>UTF-8</param-value>
  11. </init-param>
  12. <init-param>
  13. <!--是否强制设置request的编码为encoding,默认false,不建议更改-->
  14. <param-name>forceRequestEncoding</param-name>
  15. <param-value>false</param-value>
  16. </init-param>
  17. <init-param>
  18. <!--是否强制设置response的编码为encoding,建议设置为true-->
  19. <param-name>forceResponseEncoding</param-name>
  20. <param-value>true</param-value>
  21. </init-param>
  22. </filter>
  23. <filter-mapping>
  24. <filter-name>characterEncodingFilter</filter-name>
  25. <!--这里不能留空或者直接写 ' / ' ,否则可能不起作用-->
  26. <url-pattern>/*</url-pattern>
  27. </filter-mapping>

4、配置Rest风格的URI

  由于浏览器form表单只支持GET与POST请求,而DELETE、PUT等method并不支持,spring3.0添加了一个过滤器(HiddenHttpMethodFilter),可以将这些请求转换为标准的http方法,使得支持GET、POST、PUT与DELETE请求。

  1. 【在web.xml中配置】
  2.  
  3. <!-- step4: 配置过滤器,将post请求转为deleteput -->
  4. <filter>
  5. <filter-name>HiddenHttpMethodFilter</filter-name>
  6. <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  7. </filter>
  8. <filter-mapping>
  9. <filter-name>HiddenHttpMethodFilter</filter-name>
  10. <url-pattern>/*</url-pattern>
  11. </filter-mapping>

注:

  web.xml 的加载顺序是:[context-param -> listener -> filter -> servlet -> spring] ,而同类型节点之间的实际程序调用的时候的顺序是根据对应的 mapping 的顺序进行调用的。

5、web.xml完整配置

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  5. version="3.1">
  6.  
  7. <!-- step1: 配置全局的参数,启动Spring容器 -->
  8. <context-param>
  9. <param-name>contextConfigLocation</param-name>
  10. <!-- 若没有提供值,默认会去找/WEB-INF/applicationContext.xml。 -->
  11. <param-value>classpath:applicationContext.xml</param-value>
  12. </context-param>
  13. <listener>
  14. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  15. </listener>
  16.  
  17. <!-- step2: 配置SpringMVC的前端控制器,用于拦截所有的请求 -->
  18. <servlet>
  19. <servlet-name>springmvcDispatcherServlet</servlet-name>
  20. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  21.  
  22. <init-param>
  23. <param-name>contextConfigLocation</param-name>
  24. <!-- 若没有提供值,默认会去找WEB-INF/*-servlet.xml。 -->
  25. <param-value>classpath:dispatcher-servlet.xml</param-value>
  26. </init-param>
  27. <!-- 启动优先级,数值越小优先级越大 -->
  28. <load-on-startup>1</load-on-startup>
  29. </servlet>
  30. <servlet-mapping>
  31. <servlet-name>springmvcDispatcherServlet</servlet-name>
  32. <!-- 将DispatcherServlet请求映射配置为"/",则Spring MVC将捕获Web容器所有的请求,包括静态资源的请求 -->
  33. <url-pattern>/</url-pattern>
  34. </servlet-mapping>
  35.  
  36. <!-- step3: characterEncodingFilter字符编码过滤器,放在所有过滤器的前面 -->
  37. <filter>
  38. <filter-name>characterEncodingFilter</filter-name>
  39. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  40. <init-param>
  41. <!--要使用的字符集,一般我们使用UTF-8(保险起见UTF-8最好)-->
  42. <param-name>encoding</param-name>
  43. <param-value>UTF-8</param-value>
  44. </init-param>
  45. <init-param>
  46. <!--是否强制设置request的编码为encoding,默认false,不建议更改-->
  47. <param-name>forceRequestEncoding</param-name>
  48. <param-value>false</param-value>
  49. </init-param>
  50. <init-param>
  51. <!--是否强制设置response的编码为encoding,建议设置为true-->
  52. <param-name>forceResponseEncoding</param-name>
  53. <param-value>true</param-value>
  54. </init-param>
  55. </filter>
  56. <filter-mapping>
  57. <filter-name>characterEncodingFilter</filter-name>
  58. <!--这里不能留空或者直接写 ' / ' ,否则可能不起作用-->
  59. <url-pattern>/*</url-pattern>
  60. </filter-mapping>
  61.  
  62. <!-- step4: 配置过滤器,将post请求转为delete,put -->
  63. <filter>
  64. <filter-name>HiddenHttpMethodFilter</filter-name>
  65. <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  66. </filter>
  67. <filter-mapping>
  68. <filter-name>HiddenHttpMethodFilter</filter-name>
  69. <url-pattern>/*</url-pattern>
  70. </filter-mapping>
  71. </web-app>

三、(3.2)配置SpringMVC--dispatcher-servlet.xml

1、配置组件扫描方式

  用于获取相关组件。 一般在SpringMVC的配置里,只扫描Controller层,Spring配置中扫描所有包,但是排除Controller层。

  1. 【在dispatcher-servlet.xml中配置】
  2.  
  3. <!-- step1: 配置Controller扫描方式 -->
  4. <!-- 使用组件扫描的方式可以一次扫描多个Controller,只需指定包路径即可 -->
  5. <context:component-scan base-package="com.lyh.ssm.crud" use-default-filters="false">
  6. <!-- 一般在SpringMVC的配置里,只扫描Controller层,Spring配置中扫描所有包,但是排除Controller层。
  7. context:include-filter要注意,如果base-package扫描的不是最终包,那么其他包还是会扫描、加载,如果在SpringMVC的配置中这么做,会导致Spring不能处理事务,
  8. 所以此时需要在<context:component-scan>标签上,增加use-default-filters="false",就是真的只扫描context:include-filter包括的内容-->
  9. <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
  10. </context:component-scan>
  11.  
  12. <!-- 配置单个Controller的方式(某些特殊的情况可以使用),需要指定Controller的全限定名 -->
  13. <!-- <bean name="/get" class="com.wxisme.ssm.controller.Controller1"/> -->

2、配置视图解析器

  当设置视图名时,会自动添加前缀与后缀。

  1. 【在dispatcher-servlet.xml中配置】
  2.  
  3. <!-- step2: 配置视图解析器,设置视图名时,会自动添加上前缀与后缀 -->
  4. <bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  5. <property name="prefix" value="/WEB-INF/"/><!--设置JSP文件的目录位置-->
  6. <property name="suffix" value=".jsp"/>
  7. </bean>

3、配置请求处理(标准配置一)

  将DispatcherServlet请求映射配置为"/",则Spring MVC将捕获Web容器所有的请求(包括静态资源的请求),Spring MVC会将它们当成一个普通请求处理,因此找不到对应处理器将导致错误。所以为了使Spring框架能够捕获所有URL的请求,同时又将静态资源的请求转由Web容器处理,在将DispatcherServlet的请求映射配置为"/"前提下,使用<mvc:default-servlet-handler />,可以将静态请求交给服务器处理。

  1. 【在dispatcher-servlet.xml中配置】
  2.  
  3. <!-- 会在Spring MVC上下文中定义一个org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler,它会像一个检查员,对进入DispatcherServletURL进行筛查,如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理,如果不是静态资源的请求,才由DispatcherServlet继续处理。 -->
  4. <mvc:default-servlet-handler />

4、配置注解的处理器映射器和处理器适配器(标准配置二)

  <mvc:annotation-driven />简化了注解配置,且提供了一些高级功能,比如支持使用@Valid对javaBean进行JSR-303验证、支持使用@RequestBody、@ResponseBody。

  1. 【在dispatcher-servlet.xml中配置】
  2. 【方式一:】
  3. <!-- 配置注解的处理器映射器和处理器适配器(简化配置) -->
  4. <mvc:annotation-driven />
  5.  
  6. 【方式二:】
  7. <!-- 注解的处理器适配器 -->
  8. <!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> -->
  9. <!-- 注解的处理器映射器 -->
  10. <!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> -->

5、dispatcher-servlet.xml完整配置

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:mvc="http://www.springframework.org/schema/mvc"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/context
  9. http://www.springframework.org/schema/context/spring-context.xsd
  10. http://www.springframework.org/schema/mvc
  11. http://www.springframework.org/schema/mvc/spring-mvc.xsd">
  12.  
  13. <!-- step1: 配置Controller扫描方式 -->
  14. <!-- 使用组件扫描的方式可以一次扫描多个Controller,只需指定包路径即可 -->
  15. <context:component-scan base-package="com.lyh.ssm.crud" use-default-filters="false">
  16. <!-- 一般在SpringMVC的配置里,只扫描Controller层,Spring配置中扫描所有包,但是排除Controller层。
  17. context:include-filter要注意,如果base-package扫描的不是最终包,那么其他包还是会扫描、加载,如果在SpringMVC的配置中这么做,会导致Spring不能处理事务,
  18. 所以此时需要在<context:component-scan>标签上,增加use-default-filters="false",就是真的只扫描context:include-filter包括的内容-->
  19. <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
  20. </context:component-scan>
  21.  
  22. <!-- step2: 配置视图解析器 -->
  23. <bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  24. <property name="prefix" value="/WEB-INF/"/><!--设置JSP文件的目录位置-->
  25. <property name="suffix" value=".jsp"/>
  26. </bean>
  27.  
  28. <!-- step3: 标准配置 -->
  29. <!-- 将springmvc不能处理的请求交给 spring 容器处理 -->
  30. <mvc:default-servlet-handler/>
  31. <!-- 简化注解配置,并提供更高级的功能 -->
  32. <mvc:annotation-driven />
  33. </beans>

三、(3.3)配置Spring--applicationContext.xml

1、配置组件扫描方式

  用于获取相关组件 ,一般在Spring配置文件中扫描所有包,但是排除Controller层。

  1. 【在applicationContext.xml中配置】
  2.  
  3. <!-- step1: 配置包扫描方式。扫描所有包,但是排除Controller -->
  4. <context:component-scan base-package="com.lyh.ssm.crud">
  5. <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
  6. </context:component-scan>

2、配置数据库连接池

  用于数据库操作。

  1. 【方式一:直接填写连接参数】
  2. 【在applicationContext.xml中配置】
  3. <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
  4. <!--注入属性-->
  5. <property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
  6. <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/lyh?useUnicode=true&characterEncoding=utf8"></property>
  7. <property name="user" value="root"></property>
  8. <property name="password" value="123456"></property>
  9. </bean>
  10.  
  11. 【方式二:通过properties文件的方式获取连接参数】
  12. dbconfig.properties
  13. jdbc.driver = com.mysql.cj.jdbc.Driver
  14. jdbc.url = jdbc:mysql://localhost:3306/lyh?useUnicode=true&characterEncoding=utf8
  15. jdbc.username = root
  16. jdbc.password = 123456
  17.  
  18. 【在applicationContext.xml中配置】
  19. <!-- 引入properties文件 -->
  20. <context:property-placeholder location="classpath:dbconfig.properties" />
  21.  
  22. <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
  23. <!--注入属性-->
  24. <property name="driverClass" value="${jdbc.driverClass}"></property>
  25. <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
  26. <property name="user" value="${jdbc.user}"></property>
  27. <property name="password" value="${jdbc.password}"></property>
  28. </bean>

三、(3.4)Spring和MyBatis整合配置--applicationContext.xml

  jar包由MyBatis提供。

1、配置sqlSessionFactory

  1. 【在applicationContext.xml中配置】
  2.  
  3. <!-- step3: spring mybatis 整合 -->
  4. <!-- 配置sqlSessionFactory,需要引入 mybatis-spring -->
  5. <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  6. <!-- 加载Mybatis全局配置文件 -->
  7. <property name="configLocation" value="classpath:mybatis-config.xml"/>
  8.  
  9. <!-- 数据库连接池 -->
  10. <property name="dataSource" ref="dataSource"/>
  11.  
  12. <!-- 配置mapper文件位置,扫描映射文件 -->
  13. <property name="mapperLocations" value="classpath:mappers/*.xml"/>
  14. </bean>

2、配置批量执行的sqlSession(可选操作)

  1. 【在applicationContext.xml中配置】
  2.  
  3. <!-- step4: 配置批量执行的sqlSession(可选操作) -->
  4. <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
  5. <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
  6. <constructor-arg name="executorType" value="BATCH"/>
  7. </bean>

3、配置mapper扫描器

  1. 【在applicationContext.xml中配置】
  2.  
  3. <!-- step5: 配置mapper扫描器,将其加入到ioc容器中 -->
  4. <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  5. <!-- 扫描包路径,如果需要扫描多个包中间用半角逗号隔开 -->
  6. <property name="basePackage" value="com.lyh.ssm.crud.dao"></property>
  7. <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
  8. </bean>

4、配置事务控制与切面(可选)

  1. 【在applicationContext.xml中配置】
  2.  
  3. <!-- step6: 配置事务控制 -->
  4. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  5. <!-- 配置数据源 -->
  6. <property name="dataSource" ref="dataSource"/>
  7. </bean>
  8.  
  9. <!-- 配置事务通知 -->
  10. <tx:advice id="txAdvice" transaction-manager="transactionManager">
  11. <tx:attributes>
  12. <!-- 传播行为 -->
  13. <tx:method name="post*" propagation="REQUIRED"/>
  14. <tx:method name="put*" propagation="REQUIRED"/>
  15. <tx:method name="delete*" propagation="REQUIRED"/>
  16. <tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
  17. </tx:attributes>
  18. </tx:advice>
  19.  
  20. <!-- 配置aop -->
  21. <aop:config>
  22. <!-- 配置事务增强,指定切点表达式,第一个*表示返回任意类型,第二个*表示任意方法,(..)表示任意数量和类型的参数-->
  23. <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.lyh.ssm.crud.service..*(..))"/>
  24. </aop:config>

5、applicationContext.xml完整配置

  1. db.properties
  2. jdbc.driver = com.mysql.cj.jdbc.Driver
  3. jdbc.url = jdbc:mysql://localhost:3306/lyh?useUnicode=true&characterEncoding=utf8
  4. jdbc.username = root
  5. jdbc.password = 123456
  6.  
  7. applicationContext.xml
  8. <?xml version="1.0" encoding="UTF-8"?>
  9. <beans xmlns="http://www.springframework.org/schema/beans"
  10. xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
  11. xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
  12. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  13. xsi:schemaLocation="
  14. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
  15. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
  16. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
  17. http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
  18.  
  19. <!-- step1: 配置包扫描方式。扫描所有包,但是排除Controller -->
  20. <context:component-scan base-package="com.lyh.ssm.crud">
  21. <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
  22. </context:component-scan>
  23.  
  24. <!-- step2: 配置数据库连接信息 -->
  25. <!-- 引入properties文件 -->
  26. <context:property-placeholder location="classpath:db.properties"/>
  27.  
  28. <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
  29. <!--注入属性-->
  30. <property name="driverClass" value="${jdbc.driver}"></property>
  31. <property name="jdbcUrl" value="${jdbc.url}"></property>
  32. <property name="user" value="${jdbc.username}"></property>
  33. <property name="password" value="${jdbc.password}"></property>
  34. </bean>
  35.  
  36. <!-- step3: spring mybatis 整合 -->
  37. <!-- 配置sqlSessionFactory,需要引入 mybatis-spring -->
  38. <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  39. <!-- 加载Mybatis全局配置文件 -->
  40. <property name="configLocation" value="classpath:mybatis-config.xml"/>
  41.  
  42. <!-- 数据库连接池 -->
  43. <property name="dataSource" ref="dataSource"/>
  44.  
  45. <!-- 配置mapper文件位置,扫描映射文件 -->
  46. <property name="mapperLocations" value="classpath:mappers/*.xml"/>
  47. </bean>
  48.  
  49. <!-- step4: 配置批量执行的sqlSession(可选操作) -->
  50. <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
  51. <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
  52. <constructor-arg name="executorType" value="BATCH"/>
  53. </bean>
  54.  
  55. <!-- step5: 配置mapper扫描器,将其加入到ioc容器中 -->
  56. <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  57. <!-- 扫描包路径,如果需要扫描多个包中间用半角逗号隔开 -->
  58. <property name="basePackage" value="com.lyh.ssm.crud.dao"></property>
  59. <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
  60. </bean>
  61.  
  62. <!-- step6: 配置事务控制 -->
  63. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  64. <!-- 配置数据源 -->
  65. <property name="dataSource" ref="dataSource"/>
  66. </bean>
  67.  
  68. <!-- 配置事务通知 -->
  69. <tx:advice id="txAdvice" transaction-manager="transactionManager">
  70. <tx:attributes>
  71. <!-- 传播行为 -->
  72. <tx:method name="post*" propagation="REQUIRED"/>
  73. <tx:method name="put*" propagation="REQUIRED"/>
  74. <tx:method name="delete*" propagation="REQUIRED"/>
  75. <tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
  76. </tx:attributes>
  77. </tx:advice>
  78.  
  79. <!-- 配置aop -->
  80. <aop:config>
  81. <!-- 配置事务增强,指定切点表达式,第一个*表示返回任意类型,第二个*表示任意方法,(..)表示任意数量和类型的参数-->
  82. <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.lyh.ssm.crud.service..*(..))"/>
  83. </aop:config>
  84. </beans>

三、(3.5)Mybatis配置 -- mybatis-config.xml

1、配置全局参数

  1. 【在mybatis-config.xml中配置】
  2.  
  3. <settings>
  4. <!-- 开启驼峰命名规则 -->
  5. <setting name="mapUnderscoreToCamelCase" value="true"/>
  6. </settings>

2、使用分页插件(pagehelper)

  1. 【在mybatis-config.xml中配置】
  2.  
  3. <plugins>
  4. <!-- 使用分页插件 -->
  5. <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
  6. </plugins>

3、mybatis-config.xml 完整配置

  1. mybatis-config.xml
  2. <?xml version="1.0" encoding="UTF-8" ?>
  3. <!DOCTYPE configuration
  4. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  5. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  6. <configuration>
  7. <settings>
  8. <!-- 开启驼峰命名规则 -->
  9. <setting name="mapUnderscoreToCamelCase" value="true"/>
  10. </settings>
  11. <plugins>
  12. <!-- 使用分页插件 -->
  13. <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
  14. </plugins>
  15. </configuration>

四、逆向工程

  参考: https://www.cnblogs.com/l-y-h/p/11748300.html

1、配置文件 -- src/mybatis-generator.xml

  1. src/mybatis-generator.xml
  2. <?xml version="1.0" encoding="UTF-8"?>
  3. <!DOCTYPE generatorConfiguration
  4. PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  5. "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
  6.  
  7. <generatorConfiguration>
  8. <context id="DB2Tables" targetRuntime="MyBatis3">
  9. <!-- 清除注释信息 -->
  10. <commentGenerator>
  11. <property name="suppressAllComments" value="true" />
  12. </commentGenerator>
  13.  
  14. <!-- step1: 配置数据库连接信息 -->
  15. <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
  16. connectionURL="jdbc:mysql://localhost:3306/lyh"
  17. userId="root"
  18. password="123456">
  19. </jdbcConnection>
  20.  
  21. <javaTypeResolver>
  22. <property name="forceBigDecimals" value="false"/>
  23. </javaTypeResolver>
  24.  
  25. <!-- step2: 指定java bean生成的位置
  26. targetProject 指的是 哪个项目
  27. targetPackage 指的是 项目中的路径
  28. -->
  29. <javaModelGenerator targetPackage="com.lyh.ssm.crud.bean" targetProject=".\src">
  30. <property name="enableSubPackages" value="true"/>
  31. <property name="trimStrings" value="true"/>
  32. </javaModelGenerator>
  33.  
  34. <!-- step3:指定sql映射文件生成的位置 -->
  35. <sqlMapGenerator targetPackage="com.lyh.ssm.crud.mapper" targetProject=".\src">
  36. <property name="enableSubPackages" value="true"/>
  37. </sqlMapGenerator>
  38.  
  39. <!-- step4: 指定接口生成的位置 -->
  40. <javaClientGenerator type="XMLMAPPER" targetPackage="com.lyh.ssm.crud.dao" targetProject=".\src">
  41. <property name="enableSubPackages" value="true"/>
  42. </javaClientGenerator>
  43.  
  44. <!-- step5: 指定表的生成策略
  45. tableName 指定表名
  46. domainObjectName 指定表对应的 实体类的名字
  47. -->
  48. <table tableName="emp" domainObjectName="Employee"></table>
  49. <table tableName="dept" domainObjectName="Department"></table>
  50. </context>
  51. </generatorConfiguration>

2、执行类 -- TestMybatisGenerator

  1. import org.mybatis.generator.api.MyBatisGenerator;
  2. import org.mybatis.generator.config.Configuration;
  3. import org.mybatis.generator.config.xml.ConfigurationParser;
  4. import org.mybatis.generator.exception.InvalidConfigurationException;
  5. import org.mybatis.generator.exception.XMLParserException;
  6. import org.mybatis.generator.internal.DefaultShellCallback;
  7.  
  8. import java.io.File;
  9. import java.io.IOException;
  10. import java.sql.SQLException;
  11. import java.util.ArrayList;
  12. import java.util.List;
  13.  
  14. public class TestMybatisGenerator {
  15. public static void main(String[] args) throws IOException, XMLParserException, InvalidConfigurationException, SQLException, InterruptedException {
  16. List<String> warnings = new ArrayList<String>();
  17. boolean overwrite = true;
  18. File configFile = new File("src//mybatis-generator.xml");
  19. System.out.println(configFile);
  20. ConfigurationParser cp = new ConfigurationParser(warnings);
  21. Configuration config = cp.parseConfiguration(configFile);
  22. DefaultShellCallback callback = new DefaultShellCallback(overwrite);
  23. MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
  24. myBatisGenerator.generate(null);
  25. }
  26. }

注:

  文件生成后,位置可能不对。需手动将文件复制到相应位置。

五、数据库 (mysql 1.8)

1、创建数据表

  1. emp
  2. -- 创建一个 emp 表,其中 id 为主键且自增。
  3. CREATE TABLE emp(
  4. id int primary key auto_increment,
  5. name varchar(50),
  6. salary double,
  7. age int,
  8. email varchar(50)
  9. );
  10.  
  11. dept
  12. -- 创建一个 dept 表,其中 deptId 为自增主键
  13. CREATE TABLE dept(
  14. deptId INT(11) PRIMARY KEY AUTO_INCREMENT,
  15. deptName VARCHAR(255)
  16. );
  17.  
  18. -- emp 表增加一个列
  19. ALTER TABLE emp ADD COLUMN deptId INT(11);
  20.  
  21. -- 并将 emp 中该列作为外键关联到 dept 的主键
  22. ALTER TABLE emp ADD CONSTRAINT fk_emp_dept FOREIGN KEY(deptId) REFERENCES dept(deptId);

2、插入一些数据(可选操作)

  1. dept
  2. INSERT INTO dept(deptId, deptName) VALUES(1, '开发部');
  3. INSERT INTO dept(deptId, deptName) VALUES(2, '测试部');
  4. INSERT INTO dept(deptId, deptName) VALUES(3, '产品部');
  5.  
  6. emp(id自增,给其插个 null 即可)
  7. INSERT INTO emp(id, name, salary, age, email, deptId) VALUES(null, 'tom', '', 23, 'tom@163.com', 1);
  8. INSERT INTO emp(id, name, salary, age, email, deptId) VALUES(null, 'jarry', '', 23, 'jarry@163.com', 2);
  9. INSERT INTO emp(id, name, salary, age, email, deptId) VALUES(null, 'rick', '', 23, 'rick@163.com', 3);
  10. INSERT INTO emp(id, name, salary, age, email, deptId) VALUES(null, 'rose', '', 23, 'rose@163.com', 3);
  11. INSERT INTO emp(id, name, salary, age, email, deptId) VALUES(null, 'tim', '', 23, 'tim@163.com', 2);
  12. INSERT INTO emp(id, name, salary, age, email, deptId) VALUES(null, 'silla', '', 23, 'silla@163.com', 1);
  13. INSERT INTO emp(id, name, salary, age, email, deptId) VALUES(null, 'jack', '', 23, 'jack@163.com', 1);
  14. INSERT INTO emp(id, name, salary, age, email, deptId) VALUES(null, 'lisa', '', 23, 'lisa@163.com', 2);
  15. INSERT INTO emp(id, name, salary, age, email, deptId) VALUES(null, 'mina', '', 23, 'mina@163.com', 2);

3、测试后台代码与数据库的交互(可选操作)

  1. 【在applicationContext.xml中配置 批量执行的 sqlSession
  2. <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
  3. <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
  4. <constructor-arg name="executorType" value="BATCH"/>
  5. </bean>
  6.  
  7. 【测试类 TestCodeEnvironment.java
  8.  
  9. import com.lyh.ssm.crud.bean.Department;
  10. import com.lyh.ssm.crud.bean.Employee;
  11. import com.lyh.ssm.crud.dao.DepartmentMapper;
  12. import com.lyh.ssm.crud.dao.EmployeeMapper;
  13. import org.apache.ibatis.session.SqlSession;
  14. import org.junit.Test;
  15. import org.junit.runner.RunWith;
  16. import org.springframework.beans.factory.annotation.Autowired;
  17. import org.springframework.test.context.ContextConfiguration;
  18. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  19.  
  20. import java.util.UUID;
  21.  
  22. @RunWith(SpringJUnit4ClassRunner.class)
  23. @ContextConfiguration(locations = "classpath:applicationContext.xml")
  24. public class TestCodeEnvironment {
  25. @Autowired
  26. EmployeeMapper employeeMapper;
  27.  
  28. @Autowired
  29. DepartmentMapper departmentMapper;
  30.  
  31. @Autowired
  32. SqlSession sqlSession;
  33.  
  34. @Test
  35. public void testDept() {
  36. departmentMapper.insertSelective(new Department(null, "开发部"));
  37. departmentMapper.insertSelective(new Department(null, "测试部"));
  38. }
  39.  
  40. @Test
  41. public void testEmp() {
  42. // 批量执行 sql 语句
  43. EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
  44. for (int i = 0; i < 2; i++){
  45. String name = UUID.randomUUID().toString().substring(0, 5) + i;
  46. employeeMapper.insertSelective(new Employee(null, name, 1000.0, 20, "jarry@163.com",1));
  47. }
  48. }
  49. }

六、后端代码

1、文件结构

2、代码

  1. com.lyh.ssm.crud.model.BaseModel
  2.  
  3. package com.lyh.ssm.crud.model;
  4.  
  5. import java.util.ArrayList;
  6. import java.util.List;
  7.  
  8. /**
  9. * 基础返回类型,
  10. * messages 用于保存返回的信息
  11. * level 用于保存信息的级别
  12. * Level 为枚举类型
  13. */
  14. public class BaseModel {
  15. private List<String> messages = new ArrayList<String>();
  16. private Level level = Level.info;
  17. private Boolean success = true;
  18.  
  19. public Boolean getSuccess() {
  20. return success;
  21. }
  22.  
  23. public void setSuccess(Boolean success) {
  24. this.success = success;
  25. }
  26.  
  27. public List<String> getMessages() {
  28. return messages;
  29. }
  30.  
  31. public void setMessages(List<String> messages) {
  32. this.messages = messages;
  33. }
  34.  
  35. public Level getLevel() {
  36. return level;
  37. }
  38.  
  39. public void setLevel(Level level) {
  40. this.level = level;
  41. }
  42.  
  43. public enum Level {
  44. info,
  45. warn,
  46. error
  47. }
  48.  
  49. public void addMessage(String message) {
  50. this.messages.add(message);
  51. }
  52. }
  53.  
  54. com.lyh.ssm.crud.model.DeptModel
  55.  
  56. package com.lyh.ssm.crud.model;
  57.  
  58. import com.lyh.ssm.crud.bean.Department;
  59.  
  60. import java.util.List;
  61.  
  62. public class DeptModel extends BaseModel {
  63. private List<Department> departments;
  64.  
  65. public List<Department> getDepartments() {
  66. return departments;
  67. }
  68.  
  69. public void setDepartments(List<Department> departments) {
  70. this.departments = departments;
  71. }
  72. }
  73.  
  74. com.lyh.ssm.crud.model.EmpModel
  75.  
  76. package com.lyh.ssm.crud.model;
  77.  
  78. import com.lyh.ssm.crud.bean.Employee;
  79.  
  80. import java.util.ArrayList;
  81. import java.util.List;
  82.  
  83. /**
  84. * 员工返回信息类,用于返回员工信息
  85. */
  86. public class EmpModel extends BaseModel {
  87. private List<Employee> employeeList = new ArrayList<Employee>();
  88.  
  89. public List<Employee> getEmployeeList() {
  90. return employeeList;
  91. }
  92.  
  93. public void setEmployeeList(List<Employee> employeeList) {
  94. this.employeeList = employeeList;
  95. }
  96.  
  97. public void addEmployee(Employee emp) {
  98. this.employeeList.add(emp);
  99. }
  100. }

  101. com.lyh.ssm.crud.model.EmpPageModel
    package com.lyh.ssm.crud.model;
  102.  
  103. import com.github.pagehelper.PageInfo;
  104.  
  105. public class EmpPageModel extends BaseModel {
  106. private PageInfo pageInfo;
  107.  
  108. public PageInfo getPageInfo() {
  109. return pageInfo;
  110. }
  111.  
  112. public void setPageInfo(PageInfo pageInfo) {
  113. this.pageInfo = pageInfo;
  114. }
  115. }
  116.  
  117. com.lyh.ssm.crud.controller.EmpController
  118.  
  119. package com.lyh.ssm.crud.controller;
  120.  
  121. import com.github.pagehelper.PageHelper;
  122. import com.github.pagehelper.PageInfo;
  123. import com.lyh.ssm.crud.bean.Employee;
  124. import com.lyh.ssm.crud.model.BaseModel;
  125. import com.lyh.ssm.crud.model.EmpModel;
  126. import com.lyh.ssm.crud.model.EmpPageModel;
  127. import com.lyh.ssm.crud.service.EmpService;
  128. import org.springframework.beans.factory.annotation.Autowired;
  129. import org.springframework.web.bind.annotation.*;
  130.  
  131. import java.util.List;
  132.  
  133. @RestController
  134. public class EmpController {
  135. @Autowired
  136. private EmpService empService;
  137.  
  138. /**
  139. * 获取分页的数据
  140. * @param pageNum 获取第几页的数据
  141. * @param pageSize 返回数据的条数
  142. * @return 返回数据
  143. */
  144. @GetMapping("/emps/{pageNum}")
  145. public EmpPageModel getAllEmp(@PathVariable Integer pageNum, @RequestParam Integer pageSize) {
  146. // step1:引入分页插件(PageHelper)
  147. // step2:每次查询前,设置查询的页面以及查询的条数,每次获取5条数据
  148. PageHelper.startPage(pageNum, pageSize);
  149. // step3:执行分页查询
  150. List<Employee> employeeList = empService.getAllEmp();
  151. // step4:包装查询后的数据
  152. PageInfo pageInfo = new PageInfo(employeeList);
  153. EmpPageModel empPageModel = new EmpPageModel();
  154. if (employeeList.size() <= 0) {
  155. empPageModel.addMessage("获取分页数据失败");
  156. empPageModel.setSuccess(false);
  157. empPageModel.setLevel(BaseModel.Level.error);
  158. return empPageModel;
  159. }
  160. empPageModel.addMessage("获取分页数据成功");
  161. empPageModel.setSuccess(true);
  162. empPageModel.setLevel(BaseModel.Level.info);
  163. empPageModel.setPageInfo(pageInfo);
  164. return empPageModel;
  165. }
  166.  
  167. /**
  168. * 获取某个员工的信息
  169. * REST -- GET
  170. * @param id 员工的id
  171. * @return 返回数据
  172. */
  173. @GetMapping("/emp/{id}")
  174. public EmpModel getEmpById(@PathVariable Integer id) {
  175. EmpModel empModel = new EmpModel();
  176. if (empService.getEmpById(id) == null) {
  177. empModel.addMessage("获取员工信息失败");
  178. empModel.setSuccess(false);
  179. empModel.setLevel(BaseModel.Level.error);
  180. return empModel;
  181. }
  182. empModel.addMessage("获取员工信息成功");
  183. empModel.setSuccess(true);
  184. empModel.setLevel(BaseModel.Level.info);
  185. empModel.addEmployee(empService.getEmpById(id));
  186. return empModel;
  187. }
  188.  
  189. /**
  190. * 删除某个员工的信息
  191. * REST -- DELETE
  192. * @param id 员工的id
  193. * @return 返回数据
  194. */
  195. @RequestMapping(value = "/emp/{id}", method = RequestMethod.DELETE)
  196. public BaseModel deleteEmpById(@PathVariable Integer id) {
  197. BaseModel baseModel = new BaseModel();
  198. if (empService.deleteEmpById(id) != 0) {
  199. baseModel.addMessage("删除员工信息成功");
  200. baseModel.setSuccess(true);
  201. baseModel.setLevel(BaseModel.Level.info);
  202. return baseModel;
  203. }
  204. baseModel.addMessage("删除员工信息失败");
  205. baseModel.setSuccess(false);
  206. baseModel.setLevel(BaseModel.Level.error);
  207. return baseModel;
  208. }
  209.  
  210. /**
  211. * 向员工表中插入员工信息
  212. * REST -- POST
  213. * 使用 @RequestBody 需注意,前台传递的参数名要与 Employee 里的参数名对应,否则接收不到值
  214. * @param employee 员工信息
  215. * @return 返回数据
  216. */
  217. @PostMapping("/emp")
  218. public BaseModel insertEmp(@RequestBody Employee employee) {
  219. BaseModel baseModel = new BaseModel();
  220. if (empService.insertEmp(employee) != 0) {
  221. baseModel.addMessage("插入员工信息成功");
  222. baseModel.setSuccess(true);
  223. baseModel.setLevel(BaseModel.Level.info);
  224. return baseModel;
  225. }
  226. baseModel.addMessage("插入员工信息失败");
  227. baseModel.setSuccess(false);
  228. baseModel.setLevel(BaseModel.Level.error);
  229. return baseModel;
  230. }
  231.  
  232. /**
  233. * 更新员工信息
  234. * REST -- PUT
  235. * @param employee 员工信息
  236. * @return 返回数据
  237. */
  238. @RequestMapping(value = "/emp/{id}", method = RequestMethod.PUT)
  239. public BaseModel updateEmp(@RequestBody Employee employee) {
  240. BaseModel baseModel = new BaseModel();
  241. if (empService.updateEmp(employee) != 0) {
  242. baseModel.addMessage("更新员工信息成功");
  243. baseModel.setSuccess(true);
  244. baseModel.setLevel(BaseModel.Level.info);
  245. return baseModel;
  246. }
  247. baseModel.addMessage("更新员工信息失败");
  248. baseModel.setSuccess(false);
  249. baseModel.setLevel(BaseModel.Level.error);
  250. return baseModel;
  251. }
  252. }
  253.  
  254. com.lyh.ssm.crud.controller.DeptController
  255. package com.lyh.ssm.crud.controller;
  256.  
  257. import com.lyh.ssm.crud.model.BaseModel;
  258. import com.lyh.ssm.crud.model.DeptModel;
  259. import com.lyh.ssm.crud.service.DeptService;
  260. import org.springframework.beans.factory.annotation.Autowired;
  261. import org.springframework.web.bind.annotation.GetMapping;
  262. import org.springframework.web.bind.annotation.RestController;
  263.  
  264. @RestController
  265. public class DeptController {
  266. @Autowired
  267. private DeptService deptService;
  268.  
  269. @GetMapping("/depts")
  270. public DeptModel getAllDept() {
  271. DeptModel deptModel = new DeptModel();
  272. if (deptService.getAllDept().size() <= 0) {
  273. deptModel.addMessage("获取部门信息失败");
  274. deptModel.setSuccess(false);
  275. deptModel.setLevel(BaseModel.Level.error);
  276. return deptModel;
  277. }
  278. deptModel.addMessage("获取部门信息成功");
  279. deptModel.setSuccess(true);
  280. deptModel.setLevel(BaseModel.Level.info);
  281. deptModel.setDepartments(deptService.getAllDept());
  282. return deptModel;
  283. }
  284. }
  285.  
  286. com.lyh.ssm.crud.service.DeptService
  287. package com.lyh.ssm.crud.service;
  288.  
  289. import com.lyh.ssm.crud.bean.Department;
  290. import com.lyh.ssm.crud.dao.DepartmentMapper;
  291. import org.springframework.beans.factory.annotation.Autowired;
  292. import org.springframework.stereotype.Service;
  293.  
  294. import java.util.List;
  295.  
  296. @Service
  297. public class DeptService {
  298. @Autowired
  299. private DepartmentMapper departmentMapper;
  300.  
  301. public List<Department> getAllDept() {
  302. return departmentMapper.selectAll();
  303. }
  304. }
  305.  
  306. com.lyh.ssm.crud.service.EmpService
  307. package com.lyh.ssm.crud.service;
  308.  
  309. import com.lyh.ssm.crud.bean.Employee;
  310. import com.lyh.ssm.crud.dao.EmployeeMapper;
  311. import org.springframework.beans.factory.annotation.Autowired;
  312. import org.springframework.stereotype.Service;
  313.  
  314. import java.util.List;
  315.  
  316. @Service
  317. public class EmpService {
  318. @Autowired
  319. private EmployeeMapper employeeMapper;
  320.  
  321. /**
  322. * 获取某个员工的信息
  323. *
  324. * @param id 某个员工的id
  325. * @return 某个员工的信息
  326. */
  327. public Employee getEmpById(Integer id) {
  328. return employeeMapper.selectByPrimaryKey(id);
  329. }
  330.  
  331. /**
  332. * 获取所有员工的信息
  333. *
  334. * @return 所有员工的信息
  335. */
  336. public List<Employee> getAllEmp() {
  337. return employeeMapper.selectAll();
  338. }
  339.  
  340. /**
  341. * 插入某个员工的信息
  342. *
  343. * @param emp 某员工的信息
  344. * @return 返回插入影响的行数
  345. */
  346. public Integer insertEmp(Employee emp) {
  347. return employeeMapper.insertSelective(emp);
  348. }
  349.  
  350. /**
  351. * 删除某个员工的信息
  352. *
  353. * @param id 员工的id
  354. * @return 返回删除影响的行数
  355. */
  356. public Integer deleteEmpById(Integer id) {
  357. return employeeMapper.deleteByPrimaryKey(id);
  358. }
  359.  
  360. /**
  361. * 更新某个员工的信息
  362. * @param employee 员工信息
  363. * @return 返回修改影响的行数
  364. */
  365. public Integer updateEmp(Employee employee) {
  366. return employeeMapper.updateByPrimaryKeySelective(employee);
  367. }
  368. }
  369.  
  370. com.lyh.ssm.crud.dao.DepartmentMapper
    package com.lyh.ssm.crud.dao;
  371.  
  372. import com.lyh.ssm.crud.bean.Department;
  373. import com.lyh.ssm.crud.bean.DepartmentExample;
  374. import java.util.List;
  375. import org.apache.ibatis.annotations.Param;
  376.  
  377. public interface DepartmentMapper {
  378. long countByExample(DepartmentExample example);
  379.  
  380. int deleteByExample(DepartmentExample example);
  381.  
  382. int deleteByPrimaryKey(Integer deptid);
  383.  
  384. int insert(Department record);
  385.  
  386. int insertSelective(Department record);
  387.  
  388. List<Department> selectByExample(DepartmentExample example);
  389.  
  390. Department selectByPrimaryKey(Integer deptid);
  391.  
  392. int updateByExampleSelective(@Param("record") Department record, @Param("example") DepartmentExample example);
  393.  
  394. int updateByExample(@Param("record") Department record, @Param("example") DepartmentExample example);
  395.  
  396. int updateByPrimaryKeySelective(Department record);
  397.  
  398. int updateByPrimaryKey(Department record);
  399.  
  400. List<Department> selectAll();
  401. }
  402.  
  403. com.lyh.ssm.crud.dao.EmployeeMapper
    package com.lyh.ssm.crud.dao;
  404.  
  405. import com.lyh.ssm.crud.bean.Employee;
  406. import com.lyh.ssm.crud.bean.EmployeeExample;
  407.  
  408. import java.util.List;
  409.  
  410. import org.apache.ibatis.annotations.Param;
  411.  
  412. public interface EmployeeMapper {
  413. long countByExample(EmployeeExample example);
  414.  
  415. int deleteByExample(EmployeeExample example);
  416.  
  417. int deleteByPrimaryKey(Integer id);
  418.  
  419. int insert(Employee record);
  420.  
  421. int insertSelective(Employee record);
  422.  
  423. List<Employee> selectByExample(EmployeeExample example);
  424.  
  425. List<Employee> selectAll();
  426.  
  427. Employee selectByPrimaryKey(Integer id);
  428.  
  429. int updateByExampleSelective(@Param("record") Employee record, @Param("example") EmployeeExample example);
  430.  
  431. int updateByExample(@Param("record") Employee record, @Param("example") EmployeeExample example);
  432.  
  433. int updateByPrimaryKeySelective(Employee record);
  434.  
  435. int updateByPrimaryKey(Employee record);
  436. }
  437.  
  438. mappers/DepartmentMapper.xml 添加方法】
  439. <select id="selectAll" resultMap="BaseResultMap">
  440. select
  441. <include refid="Base_Column_List" />
  442. from dept
  443. </select>
  444.  
  445. mappers/EmployeeMapper.xml
  446. <select id="selectAll" resultMap="BaseResultMap">
  447. SELECT e.id AS id, e.name AS name, e.salary AS salary, e.age AS age, e.email AS email, d.deptId AS deptId, d.deptName AS deptName
  448. FROM emp e
  449. LEFT JOIN dept d
  450. ON e.deptId = d.deptId
  451. ORDER BY e.id
  452. </select>
  453.  
  454. <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
  455. SELECT e.id AS id, e.name AS name, e.salary AS salary, e.age AS age, e.email AS email, d.deptId AS deptId, d.deptName AS deptName
  456. FROM emp e
  457. LEFT JOIN dept d
  458. ON e.deptId = d.deptId
  459. WHERE e.id = #{id,jdbcType=INTEGER}
  460. </select>

七、前端代码--静态页面

1、非 template/render 模式下

此时 部分组件名前 需加前缀 i- 才可使用。

比如:

  Button  -->  i-button

  Table    -->  i-table

  Select  -->  i-select

  Option  -->  i-option

  Form    -->  i-form

  FormItem  -->  form-item

  1. 【非 template/render 模式下】
  2.  
  3. <!DOCTYPE html>
  4. <html>
  5. <head>
  6. <meta charset="utf-8">
  7. <title>ViewUI example</title>
  8. <link rel="stylesheet" type="text/css" href="http://unpkg.com/view-design/dist/styles/iview.css">
  9. <script type="text/javascript" src="http://vuejs.org/js/vue.min.js"></script>
  10. <script type="text/javascript" src="http://unpkg.com/view-design/dist/iview.min.js"></script>
  11. </head>
  12. <body>
  13. <div id="app">
  14. <div style="width: 1200px; margin: 0 auto;" class="layout">
  15. <Layout>
  16. <header>
  17. <row>
  18. <Divider orientation="left">
  19. <h1>员工列表</h1>
  20. </Divider>
  21. </row>
  22. <row justify="end" type="flex">
  23. <i-col style="margin-right: 5px"><i-button type="primary" icon="md-add" @click="create">添加</i-button></i-col>
  24. <i-col style="margin-right: 5px"><i-button type="success" icon="md-settings" @click="setUp = true">设置</i-button></i-col>
  25. </row>
  26. </header>
  27. <Content>
  28. <i-table :data="data2" :columns="tableColumns1" :stripe="showStripe" :border="showBorder" :showHeader="showHeader" :size="tableSize" :height="fixedHeader ? 250 : ''">
  29. <template slot-scope="{ row }" slot="name">
  30. <strong>{{ row.name }}</strong>
  31. </template>
  32. <template slot-scope="{ row, index }" slot="action">
  33. <i-button type="primary" size="small" style="margin-right: 5px" @click="show(index)" icon="ios-create-outline">编辑</i-button>
  34. <i-button type="error" size="small" @click="remove(index)" icon="ios-trash">删除</i-button>
  35. </template>
  36. </i-table>
  37. <div style="margin: 10px;overflow: hidden">
  38. <div style="float: right;">
  39. <!-- current 设置当前选中页,pageSize 设置每页显示数据的条数-->
  40. <Page :total="data1.length" :pageSize="pageSize" :current="currentPage" @on-change="changePage" show-sizer show-elevator show-total @on-page-size-change="changePageSize"></Page>
  41. </div>
  42. </div>
  43. </Content>
  44. </Layout>
  45.  
  46. <Drawer title="Set up" :closable="true" :mask="false" v-model="setUp">
  47. <div style="margin: 10px">
  48. Table Setting<br>
  49. <i-switch v-model="showBorder" style="margin-right: 5px"></i-switch>Display border<br>
  50. <i-switch v-model="showStripe" style="margin-right: 5px"></i-switch>Display stripe<br>
  51. <i-switch v-model="showIndex" style="margin-right: 5px"></i-switch>Display index<br>
  52. <i-switch v-model="showCheckbox" style="margin-right: 5px"></i-switch>Display multi choice<br>
  53. <i-switch v-model="showHeader" style="margin-right: 5px"></i-switch>Display header<br>
  54. <i-switch v-model="fixedHeader" style="margin-right: 5px"></i-switch>Table scrolling<br>
  55. <br><br>
  56.  
  57. Table size
  58. <i-select v-model="tableSize" style="width:200px">
  59. <i-option value="large">large</i-option>
  60. <i-option value="default">medium(default)</i-option>
  61. <i-option value="small">small</i-option>
  62. </i-select>
  63. </div>
  64. </Drawer>
  65.  
  66. <Modal v-model="empModal" title="Emp Info" @on-ok="okEditor" @on-cancel="cancelEditor">
  67. <i-form :label-width="80">
  68. <form-item label="Name:">
  69. <i-input v-model="empInfo.name" placeholder="Name..." style="width: 300px;" />
  70. </form-item>
  71. <form-item label="Salary:">
  72. <i-input v-model="empInfo.salary" placeholder="Salary..." style="width: 300px;" />
  73. </form-item>
  74. <form-item label="Age:">
  75. <i-input v-model="empInfo.age" placeholder="Age..." style="width: 300px;" />
  76. </form-item>
  77. <form-item label="Email:">
  78. <i-input v-model="empInfo.email" placeholder="Email..." style="width: 300px;" />
  79. </form-item>
  80. <form-item label="DeptName:">
  81. <i-select v-model="empInfo.deptName">
  82. <i-option v-for="(item, index) in dept" :key="index" :value="item.deptName"> {{item.deptName}} </i-option>
  83. </i-select>
  84. </form-item>
  85. </i-form>
  86. </Modal>
  87. </div>
  88. </div>
  89. <script>
  90. new Vue({
  91. el: '#app',
  92. data() {
  93. return {
  94. // 添加与编辑复用 modal 框,false为添加,true为编辑
  95. createOrEditor: false,
  96. // 是否打开员工信息框
  97. empModal: false,
  98. // 用于保存一个员工的信息
  99. empInfo: {},
  100. // 是否打开设置
  101. setUp: false,
  102. // 当前页码
  103. currentPage: 1,
  104. // 每页数据的条数
  105. pageSize: 10,
  106. // 表格的列
  107. tableColumns1: [{
  108. // 分页时,若要出现自动索引,设置type = "index2",并使用 render 来返回索引值
  109. type: 'index2',
  110. width: 80,
  111. align: 'center',
  112. render: (h, params) => {
  113. return h('span', params.index + (this.currentPage - 1) * this.pageSize + 1);
  114. }
  115. }, {
  116. title: 'Name',
  117. slot: 'name'
  118. }, {
  119. title: 'Salary',
  120. key: 'salary',
  121. sortable: true
  122. },
  123. {
  124. title: 'Age',
  125. key: 'age',
  126. sortable: true
  127. },
  128. {
  129. title: 'Email',
  130. key: 'email'
  131. }, {
  132. title: 'DeptName',
  133. key: 'deptName'
  134. },
  135. {
  136. title: 'Action',
  137. slot: 'action',
  138. width: 200,
  139. align: 'center'
  140. }
  141. ],
  142. dept: [{
  143. deptId: '1',
  144. deptName: '开发部'
  145. },{
  146. deptId: '2',
  147. deptName: '测试部'
  148. },{
  149. deptId: '3',
  150. deptName: '产品部'
  151. }],
  152. // 表格的源数据
  153. data1: [{
  154. name: 'John Brown',
  155. salary: 6000,
  156. age: 18,
  157. email: '323@163.com',
  158. deptId: '1',
  159. deptName: '开发部'
  160. },
  161. {
  162. name: 'Jim Green',
  163. salary: 6000,
  164. age: 24,
  165. email: '323@163.com',
  166. deptId: '2',
  167. deptName: '测试部'
  168. },
  169. {
  170. name: 'Joe Black',
  171. salary: 6000,
  172. age: 30,
  173. email: '323@163.com',
  174. deptId: '3',
  175. deptName: '产品部'
  176. },
  177. {
  178. name: 'Jon Snow',
  179. salary: 6000,
  180. age: 26,
  181. email: '323@163.com',
  182. deptId: '1',
  183. deptName: '开发部'
  184. }, {
  185. name: 'John Brown',
  186. salary: 6000,
  187. age: 18,
  188. email: '323@163.com',
  189. deptId: '2',
  190. deptName: '测试部'
  191. },
  192. {
  193. name: 'Jim Green',
  194. salary: 6000,
  195. age: 24,
  196. email: '323@163.com',
  197. deptId: '1',
  198. deptName: '开发部'
  199. },
  200. {
  201. name: 'Joe Black',
  202. salary: 6000,
  203. age: 30,
  204. email: '323@163.com',
  205. deptId: '1',
  206. deptName: '开发部'
  207. },
  208. {
  209. name: 'Jon Snow',
  210. salary: 6000,
  211. age: 26,
  212. email: '323@163.com',
  213. deptId: '2',
  214. deptName: '测试部'
  215. },
  216. {
  217. name: 'Jim Green',
  218. salary: 6000,
  219. age: 24,
  220. email: '323@163.com',
  221. deptId: '1',
  222. deptName: '开发部'
  223. },
  224. {
  225. name: 'Joe Black',
  226. salary: 6000,
  227. age: 30,
  228. email: '323@163.com',
  229. deptId: '2',
  230. deptName: '测试部'
  231. },
  232. {
  233. name: 'Jon Snow',
  234. salary: 6000,
  235. age: 26,
  236. email: '323@163.com',
  237. deptId: '3',
  238. deptName: '产品部'
  239. }
  240. ],
  241. // 表格每页的数据
  242. data2: [],
  243. // 表格边框是否显示
  244. showBorder: false,
  245. // 表格斑马纹是否显示
  246. showStripe: false,
  247. // 表格头是否显示
  248. showHeader: true,
  249. // 表格索引是否显示
  250. showIndex: true,
  251. // 表格多选框是否显示
  252. showCheckbox: false,
  253. // 表格滚动条是否开启
  254. fixedHeader: false,
  255. // 改变表格大小
  256. tableSize: 'default'
  257. }
  258. },
  259. methods: {
  260. changePage(index) {
  261. // 改变当前的页码,并获取当前页码所拥有的数据
  262. this.currentPage = index
  263. // 注意,此处不能直接用 = 赋值。使用 = 后(指向的地址相同),修改 data2 的同时会修改 data1
  264. this.data2 = [].concat(this.data1.slice((index - 1) * this.pageSize, index * this.pageSize))
  265. },
  266. show(index) {
  267. // 弹出一个模态框,用于展示某条数据的信息
  268. this.empInfo = Object.assign(this.empInfo, this.data2[index])
  269. this.empModal = true
  270. this.createOrEditor = true
  271. this.empInfo = Object.assign(this.empInfo, {index: index})
  272. },
  273. create() {
  274. // 用于添加一条信息
  275. this.empInfo = []
  276. this.empModal = true
  277. this.createOrEditor = false
  278. },
  279. remove(index) {
  280. // 删除某条数据(删除源数据)
  281. this.data1.splice((this.currentPage - 1) * 10 + index, 1)
  282. },
  283. changePageSize(index) {
  284. // 改变每页显示的条数
  285. this.$Message.info({
  286. content: '当前页面显示条数修改为: ' + index + '条/页'
  287. })
  288. // 改变后,跳转到首页,并刷新列表
  289. this.currentPage = 1
  290. this.pageSize = index
  291. this.changePage(this.currentPage)
  292. },
  293. okEditor () {
  294. if (this.createOrEditor) {
  295. // 编辑的操作,修改数据
  296. this.data1.splice((this.currentPage - 1) * 10 + this.empInfo.index, 1, this.empInfo)
  297. } else {
  298. // 添加的操作,修改数据
  299. this.data1.push(Object.assign({}, this.empInfo))
  300. }
  301. this.empInfo = {}
  302. },
  303. cancelEditor () {
  304. // 取消编辑的操作
  305. this.$Message.info({
  306. content: '操作取消'
  307. })
  308. }
  309. },
  310. watch: {
  311. showIndex(newVal) {
  312. if (newVal) {
  313. // 为true时,在首部增加一个索引列
  314. this.tableColumns1.unshift({
  315. // 分页时,若要出现自动索引,设置type = "index2",并使用 render 来返回索引值
  316. type: 'index2',
  317. width: 80,
  318. align: 'center',
  319. render: (h, params) => {
  320. return h('span', params.index + (this.currentPage - 1) * this.pageSize + 1);
  321. }
  322. })
  323. } else {
  324. // 为false时,若首部存在索引列,则移除该列
  325. this.tableColumns1.forEach((item, index) => {
  326. if (item.type === 'index2') {
  327. this.tableColumns1.splice(index, 1)
  328. }
  329. })
  330. }
  331. },
  332. showCheckbox(newVal) {
  333. if (newVal) {
  334. // 为 true 时,在首部增加一多选框列,
  335. this.tableColumns1.unshift({
  336. type: 'selection',
  337. width: 60,
  338. align: 'center'
  339. })
  340. } else {
  341. // 为false时,若存在多选框列,则移除该列
  342. this.tableColumns1.forEach((item, index) => {
  343. if (item.type === 'selection') {
  344. this.tableColumns1.splice(index, 1)
  345. }
  346. })
  347. }
  348. },
  349. data1() {
  350. // 当列表数据改变时(比如删除某数据),触发一次刷新列表的操作
  351. if (!this.createOrEditor) {
  352. // 若为添加数据,则跳转到最后一个页面
  353. this.changePage(Math.ceil(this.data1.length / this.pageSize))
  354. } else {
  355. this.changePage(this.currentPage)
  356. }
  357. }
  358. },
  359. mounted() {
  360. // 页面加载时,触发第一次刷新列表的操作
  361. this.changePage(this.currentPage)
  362. }
  363. })
  364. </script>
  365. </body>
  366. </html>

2、template/render 模式下

(1)使用 vue-cli3.0 创建项目。

  参考地址:https://www.cnblogs.com/l-y-h/p/11241503.html

(2)使用 npm 安装使用。

  参考地址:https://www.cnblogs.com/l-y-h/p/12001549.html#_label0_1

  1. main.js
  2.  
  3. import Vue from 'vue'
  4. import App from './App.vue'
  5. // step1: 引入 ViewUI
  6. import ViewUI from 'view-design'
  7. // step2: 引入 css
  8. import 'view-design/dist/styles/iview.css'
  9.  
  10. Vue.config.productionTip = false
  11. // step3:声明使用 ViewUI
  12. Vue.use(ViewUI)
  13.  
  14. new Vue({
  15. render: h => h(App),
  16. }).$mount('#app')
  17.  
  18. App.vue
  19. <template>
  20. <div style="width: 1200px; margin: 0 auto;" class="layout">
  21. <Layout>
  22. <header>
  23. <row>
  24. <Divider orientation="left">
  25. <h1>员工列表</h1>
  26. </Divider>
  27. </row>
  28. <row justify="end" type="flex">
  29. <i-col style="margin-right: 5px"><Button type="primary" icon="md-add" @click="create">添加</Button></i-col>
  30. <i-col style="margin-right: 5px"><Button type="success" icon="md-settings" @click="setUp = true">设置</Button></i-col>
  31. </row>
  32. </header>
  33. <Content>
  34. <Table :data="data2" :columns="tableColumns1" :stripe="showStripe" :border="showBorder" :showHeader="showHeader" :size="tableSize" :height="fixedHeader ? 250 : ''">
  35. <template slot-scope="{ row }" slot="name">
  36. <strong>{{ row.name }}</strong>
  37. </template>
  38. <template slot-scope="{ row, index }" slot="action">
  39. <Button type="primary" size="small" style="margin-right: 5px" @click="show(index)" icon="ios-create-outline">编辑</Button>
  40. <Button type="error" size="small" @click="remove(index)" icon="ios-trash">删除</Button>
  41. </template>
  42. </Table>
  43. <div style="margin: 10px;overflow: hidden">
  44. <div style="float: right;">
  45. <!-- current 设置当前选中页,pageSize 设置每页显示数据的条数-->
  46. <Page :total="data1.length" :pageSize="pageSize" :current="currentPage" @on-change="changePage" show-sizer show-elevator show-total @on-page-size-change="changePageSize"></Page>
  47. </div>
  48. </div>
  49. </Content>
  50. </Layout>
  51.  
  52. <Drawer title="Set up" :closable="true" :mask="false" v-model="setUp">
  53. <div style="margin: 10px">
  54. Table Setting<br>
  55. <i-switch v-model="showBorder" style="margin-right: 5px"></i-switch>Display border<br>
  56. <i-switch v-model="showStripe" style="margin-right: 5px"></i-switch>Display stripe<br>
  57. <i-switch v-model="showIndex" style="margin-right: 5px"></i-switch>Display index<br>
  58. <i-switch v-model="showCheckbox" style="margin-right: 5px"></i-switch>Display multi choice<br>
  59. <i-switch v-model="showHeader" style="margin-right: 5px"></i-switch>Display header<br>
  60. <i-switch v-model="fixedHeader" style="margin-right: 5px"></i-switch>Table scrolling<br>
  61. <br><br>
  62.  
  63. Table size
  64. <Select v-model="tableSize" style="width:200px">
  65. <Option value="large">large</Option>
  66. <Option value="default">medium(default)</Option>
  67. <Option value="small">small</Option>
  68. </Select>
  69. </div>
  70. </Drawer>
  71.  
  72. <Modal v-model="empModal" title="Emp Info" @on-ok="okEditor" @on-cancel="cancelEditor">
  73. <Form :label-width="80">
  74. <FormItem label="Name:">
  75. <Input v-model="empInfo.name" placeholder="Name..." style="width: 300px;" />
  76. </FormItem>
  77. <FormItem label="Salary:">
  78. <Input v-model="empInfo.salary" placeholder="Salary..." style="width: 300px;" />
  79. </FormItem>
  80. <FormItem label="Age:">
  81. <Input v-model="empInfo.age" placeholder="Age..." style="width: 300px;" />
  82. </FormItem>
  83. <FormItem label="Email:">
  84. <Input v-model="empInfo.email" placeholder="Email..." style="width: 300px;" />
  85. </FormItem>
  86. <FormItem label="DeptName:">
  87. <Select v-model="empInfo.deptName">
  88. <Option v-for="(item, index) in dept" :key="index" :value="item.deptName"> {{item.deptName}} </Option>
  89. </Select>
  90. </FormItem>
  91. </Form>
  92. </Modal>
  93. </div>
  94. </template>
  95. <script>
  96. export default {
  97. data() {
  98. return {
  99. // 添加与编辑复用 modal 框,false为添加,true为编辑
  100. createOrEditor: false,
  101. // 是否打开员工信息框
  102. empModal: false,
  103. // 用于保存一个员工的信息
  104. empInfo: {},
  105. // 是否打开设置
  106. setUp: false,
  107. // 当前页码
  108. currentPage: 1,
  109. // 每页数据的条数
  110. pageSize: 10,
  111. // 表格的列
  112. tableColumns1: [{
  113. // 分页时,若要出现自动索引,设置type = "index2",并使用 render 来返回索引值
  114. type: 'index2',
  115. width: 80,
  116. align: 'center',
  117. render: (h, params) => {
  118. return h('span', params.index + (this.currentPage - 1) * this.pageSize + 1);
  119. }
  120. }, {
  121. title: 'Name',
  122. slot: 'name'
  123. }, {
  124. title: 'Salary',
  125. key: 'salary',
  126. sortable: true
  127. },
  128. {
  129. title: 'Age',
  130. key: 'age',
  131. sortable: true
  132. },
  133. {
  134. title: 'Email',
  135. key: 'email'
  136. }, {
  137. title: 'DeptName',
  138. key: 'deptName'
  139. },
  140. {
  141. title: 'Action',
  142. slot: 'action',
  143. width: 200,
  144. align: 'center'
  145. }
  146. ],
  147. dept: [{
  148. deptId: '1',
  149. deptName: '开发部'
  150. },{
  151. deptId: '2',
  152. deptName: '测试部'
  153. },{
  154. deptId: '3',
  155. deptName: '产品部'
  156. }],
  157. // 表格的源数据
  158. data1: [{
  159. name: 'John Brown',
  160. salary: 6000,
  161. age: 18,
  162. email: '323@163.com',
  163. deptId: '1',
  164. deptName: '开发部'
  165. },
  166. {
  167. name: 'Jim Green',
  168. salary: 6000,
  169. age: 24,
  170. email: '323@163.com',
  171. deptId: '2',
  172. deptName: '测试部'
  173. },
  174. {
  175. name: 'Joe Black',
  176. salary: 6000,
  177. age: 30,
  178. email: '323@163.com',
  179. deptId: '3',
  180. deptName: '产品部'
  181. },
  182. {
  183. name: 'Jon Snow',
  184. salary: 6000,
  185. age: 26,
  186. email: '323@163.com',
  187. deptId: '1',
  188. deptName: '开发部'
  189. }, {
  190. name: 'John Brown',
  191. salary: 6000,
  192. age: 18,
  193. email: '323@163.com',
  194. deptId: '2',
  195. deptName: '测试部'
  196. },
  197. {
  198. name: 'Jim Green',
  199. salary: 6000,
  200. age: 24,
  201. email: '323@163.com',
  202. deptId: '1',
  203. deptName: '开发部'
  204. },
  205. {
  206. name: 'Joe Black',
  207. salary: 6000,
  208. age: 30,
  209. email: '323@163.com',
  210. deptId: '1',
  211. deptName: '开发部'
  212. },
  213. {
  214. name: 'Jon Snow',
  215. salary: 6000,
  216. age: 26,
  217. email: '323@163.com',
  218. deptId: '2',
  219. deptName: '测试部'
  220. },
  221. {
  222. name: 'Jim Green',
  223. salary: 6000,
  224. age: 24,
  225. email: '323@163.com',
  226. deptId: '1',
  227. deptName: '开发部'
  228. },
  229. {
  230. name: 'Joe Black',
  231. salary: 6000,
  232. age: 30,
  233. email: '323@163.com',
  234. deptId: '2',
  235. deptName: '测试部'
  236. },
  237. {
  238. name: 'Jon Snow',
  239. salary: 6000,
  240. age: 26,
  241. email: '323@163.com',
  242. deptId: '3',
  243. deptName: '产品部'
  244. }
  245. ],
  246. // 表格每页的数据
  247. data2: [],
  248. // 表格边框是否显示
  249. showBorder: false,
  250. // 表格斑马纹是否显示
  251. showStripe: false,
  252. // 表格头是否显示
  253. showHeader: true,
  254. // 表格索引是否显示
  255. showIndex: true,
  256. // 表格多选框是否显示
  257. showCheckbox: false,
  258. // 表格滚动条是否开启
  259. fixedHeader: false,
  260. // 改变表格大小
  261. tableSize: 'default'
  262. }
  263. },
  264. methods: {
  265. changePage(index) {
  266. // 改变当前的页码,并获取当前页码所拥有的数据
  267. this.currentPage = index
  268. // 注意,此处不能直接用 = 赋值。使用 = 后(指向的地址相同),修改 data2 的同时会修改 data1
  269. this.data2 = [].concat(this.data1.slice((index - 1) * this.pageSize, index * this.pageSize))
  270. },
  271. show(index) {
  272. // 弹出一个模态框,用于展示某条数据的信息
  273. this.empInfo = Object.assign(this.empInfo, this.data2[index])
  274. this.empModal = true
  275. this.createOrEditor = true
  276. this.empInfo = Object.assign(this.empInfo, {index: index})
  277. },
  278. create() {
  279. // 用于添加一条信息
  280. this.empInfo = []
  281. this.empModal = true
  282. this.createOrEditor = false
  283. },
  284. remove(index) {
  285. // 删除某条数据(删除源数据)
  286. this.data1.splice((this.currentPage - 1) * 10 + index, 1)
  287. },
  288. changePageSize(index) {
  289. // 改变每页显示的条数
  290. this.$Message.info({
  291. content: '当前页面显示条数修改为: ' + index + '条/页'
  292. })
  293. // 改变后,跳转到首页,并刷新列表
  294. this.currentPage = 1
  295. this.pageSize = index
  296. this.changePage(this.currentPage)
  297. },
  298. okEditor () {
  299. if (this.createOrEditor) {
  300. // 编辑的操作,修改数据
  301. this.data1.splice((this.currentPage - 1) * 10 + this.empInfo.index, 1, this.empInfo)
  302. } else {
  303. // 添加的操作,修改数据
  304. this.data1.push(Object.assign({}, this.empInfo))
  305. }
  306. this.empInfo = {}
  307. },
  308. cancelEditor () {
  309. // 取消编辑的操作
  310. this.$Message.info({
  311. content: '操作取消'
  312. })
  313. }
  314. },
  315. watch: {
  316. showIndex(newVal) {
  317. if (newVal) {
  318. // 为true时,在首部增加一个索引列
  319. this.tableColumns1.unshift({
  320. // 分页时,若要出现自动索引,设置type = "index2",并使用 render 来返回索引值
  321. type: 'index2',
  322. width: 80,
  323. align: 'center',
  324. render: (h, params) => {
  325. return h('span', params.index + (this.currentPage - 1) * this.pageSize + 1);
  326. }
  327. })
  328. } else {
  329. // 为false时,若首部存在索引列,则移除该列
  330. this.tableColumns1.forEach((item, index) => {
  331. if (item.type === 'index2') {
  332. this.tableColumns1.splice(index, 1)
  333. }
  334. })
  335. }
  336. },
  337. showCheckbox(newVal) {
  338. if (newVal) {
  339. // 为 true 时,在首部增加一多选框列,
  340. this.tableColumns1.unshift({
  341. type: 'selection',
  342. width: 60,
  343. align: 'center'
  344. })
  345. } else {
  346. // 为false时,若存在多选框列,则移除该列
  347. this.tableColumns1.forEach((item, index) => {
  348. if (item.type === 'selection') {
  349. this.tableColumns1.splice(index, 1)
  350. }
  351. })
  352. }
  353. },
  354. data1() {
  355. // 当列表数据改变时(比如删除某数据),触发一次刷新列表的操作
  356. if (!this.createOrEditor) {
  357. // 若为添加数据,则跳转到最后一个页面
  358. this.changePage(Math.ceil(this.data1.length / this.pageSize))
  359. } else {
  360. this.changePage(this.currentPage)
  361. }
  362. }
  363. },
  364. mounted() {
  365. // 页面加载时,触发第一次刷新列表的操作
  366. this.changePage(this.currentPage)
  367. }
  368. }
  369. </script>

文件目录结构:

八、前端代码

1、解决跨域问题

  可以参考:https://www.cnblogs.com/l-y-h/p/11815452.html

(1)在 main.js 中配置 baseURL

  1. main.js
  2.  
  3. import Vue from 'vue'
  4. import App from './App.vue'
  5. import ViewUI from 'view-design'
  6. import 'view-design/dist/styles/iview.css'
  7. import Axios from 'axios'
  8.  
  9. Vue.config.productionTip = false
  10. Vue.use(ViewUI)
  11. Vue.prototype.$axios = Axios
  12. Axios.defaults.baseURL = '/api'
  13.  
  14. new Vue({
  15. render: h => h(App),
  16. }).$mount('#app')

(2)在 vue.config.js 中配置跨域代理

  1. vue.config.js
  2.  
  3. module.exports = {
  4. devServer: {
  5. proxy: {
  6. '/api': {
  7. // 此处的写法,目的是为了 将 /api 替换成 http://localhost:9000/crud
  8. target: 'http://localhost:9000/crud/',
  9. // 允许跨域
  10. changeOrigin: true,
  11. ws: true,
  12. pathRewrite: {
  13. '^/api': ''
  14. }
  15. }
  16. }
  17. }
  18. }

(3)使用 axios

  1. 【自定义一个 api.js 文件】
  2.  
  3. import Axios from 'axios'
  4.  
  5. export function getAllEmps(params) {
  6. return new Promise((resolve, reject) => {
  7. Axios.get('/emps/' + params.pageNum, {
  8. params
  9. }).then(res => {
  10. resolve(res);
  11. }).catch(res => {
  12. reject(res)
  13. })
  14. })
  15. }
  16.  
  17. 【使用时,在需要使用的地方引入这个js文件即可】
  18. <template>
  19. </template>
  20. <script>
  21. import { getAllEmps } from './api/api.js'
  22. export default {
  23. data() {
  24. return {
  25. currentPage: 1,
  26. pageSize: 2
  27. }
  28. },
  29. mounted() {
  30. // 不需要使用 this.getAllEmps(),直接使用 getAllEmps() 即可
  31. getAllEmps({
  32. pageNum: this.currentPage,
  33. pageSize: this.pageSize
  34. })
  35. }
  36. }
  37. </script>
  38.  
  39. App.vue
  40.  
  41. <template>
  42. <div style="width: 1200px; margin: 0 auto;" class="layout">
  43. <Layout>
  44. <header>
  45. <row>
  46. <Divider orientation="left">
  47. <h1>员工列表</h1>
  48. </Divider>
  49. </row>
  50. <row justify="end" type="flex">
  51. <i-col style="margin-right: 5px"><Button type="primary" icon="md-add" @click="create">添加</Button></i-col>
  52. <i-col style="margin-right: 5px"><Button type="success" icon="md-settings" @click="setUp = true">设置</Button></i-col>
  53. </row>
  54. </header>
  55. <Content>
  56. <Table :data="data2" :columns="tableColumns1" :stripe="showStripe" :border="showBorder" :showHeader="showHeader" :size="tableSize" :height="fixedHeader ? 250 : ''">
  57. <template slot-scope="{ row }" slot="name">
  58. <strong>{{ row.name }}</strong>
  59. </template>
  60. <template slot-scope="{ row, index }" slot="action">
  61. <Button type="primary" size="small" style="margin-right: 5px" @click="show(index)" icon="ios-create-outline">编辑</Button>
  62. <Button type="error" size="small" @click="remove(index)" icon="ios-trash">删除</Button>
  63. </template>
  64. </Table>
  65. <div style="margin: 10px;overflow: hidden">
  66. <div style="float: right;">
  67. <!-- current 设置当前选中页,pageSize 设置每页显示数据的条数-->
  68. <Page :total="data1.length" :pageSize="pageSize" :current="currentPage" @on-change="changePage" show-sizer show-elevator show-total @on-page-size-change="changePageSize"></Page>
  69. </div>
  70. </div>
  71. </Content>
  72. </Layout>
  73.  
  74. <Drawer title="Set up" :closable="true" :mask="false" v-model="setUp">
  75. <div style="margin: 10px">
  76. Table Setting<br>
  77. <i-switch v-model="showBorder" style="margin-right: 5px"></i-switch>Display border<br>
  78. <i-switch v-model="showStripe" style="margin-right: 5px"></i-switch>Display stripe<br>
  79. <i-switch v-model="showIndex" style="margin-right: 5px"></i-switch>Display index<br>
  80. <i-switch v-model="showCheckbox" style="margin-right: 5px"></i-switch>Display multi choice<br>
  81. <i-switch v-model="showHeader" style="margin-right: 5px"></i-switch>Display header<br>
  82. <i-switch v-model="fixedHeader" style="margin-right: 5px"></i-switch>Table scrolling<br>
  83. <br><br>
  84.  
  85. Table size
  86. <Select v-model="tableSize" style="width:200px">
  87. <Option value="large">large</Option>
  88. <Option value="default">medium(default)</Option>
  89. <Option value="small">small</Option>
  90. </Select>
  91. </div>
  92. </Drawer>
  93.  
  94. <Modal v-model="empModal" title="Emp Info" @on-ok="okEditor" @on-cancel="cancelEditor">
  95. <Form :label-width="80">
  96. <FormItem label="Name:">
  97. <Input v-model="empInfo.name" placeholder="Name..." style="width: 300px;" />
  98. </FormItem>
  99. <FormItem label="Salary:">
  100. <Input v-model="empInfo.salary" placeholder="Salary..." style="width: 300px;" />
  101. </FormItem>
  102. <FormItem label="Age:">
  103. <Input v-model="empInfo.age" placeholder="Age..." style="width: 300px;" />
  104. </FormItem>
  105. <FormItem label="Email:">
  106. <Input v-model="empInfo.email" placeholder="Email..." style="width: 300px;" />
  107. </FormItem>
  108. <FormItem label="DeptName:">
  109. <Select v-model="empInfo.deptName">
  110. <Option v-for="(item, index) in dept" :key="index" :value="item.deptName"> {{item.deptName}} </Option>
  111. </Select>
  112. </FormItem>
  113. </Form>
  114. </Modal>
  115. </div>
  116. </template>
  117. <script>
  118. import { getAllEmps } from './api/api.js'
  119. export default {
  120. data() {
  121. return {
  122. // 添加与编辑复用 modal 框,false为添加,true为编辑
  123. createOrEditor: false,
  124. // 是否打开员工信息框
  125. empModal: false,
  126. // 用于保存一个员工的信息
  127. empInfo: {},
  128. // 是否打开设置
  129. setUp: false,
  130. // 当前页码
  131. currentPage: 1,
  132. // 每页数据的条数
  133. pageSize: 10,
  134. // 表格的列
  135. tableColumns1: [{
  136. // 分页时,若要出现自动索引,设置type = "index2",并使用 render 来返回索引值
  137. type: 'index2',
  138. width: 80,
  139. align: 'center',
  140. render: (h, params) => {
  141. return h('span', params.index + (this.currentPage - 1) * this.pageSize + 1);
  142. }
  143. }, {
  144. title: 'Name',
  145. slot: 'name'
  146. }, {
  147. title: 'Salary',
  148. key: 'salary',
  149. sortable: true
  150. },
  151. {
  152. title: 'Age',
  153. key: 'age',
  154. sortable: true
  155. },
  156. {
  157. title: 'Email',
  158. key: 'email'
  159. }, {
  160. title: 'DeptName',
  161. key: 'deptName'
  162. },
  163. {
  164. title: 'Action',
  165. slot: 'action',
  166. width: 200,
  167. align: 'center'
  168. }
  169. ],
  170. dept: [{
  171. deptId: '1',
  172. deptName: '开发部'
  173. },{
  174. deptId: '2',
  175. deptName: '测试部'
  176. },{
  177. deptId: '3',
  178. deptName: '产品部'
  179. }],
  180. // 表格的源数据
  181. data1: [{
  182. name: 'John Brown',
  183. salary: 6000,
  184. age: 18,
  185. email: '323@163.com',
  186. deptId: '1',
  187. deptName: '开发部'
  188. },
  189. {
  190. name: 'Jim Green',
  191. salary: 6000,
  192. age: 24,
  193. email: '323@163.com',
  194. deptId: '2',
  195. deptName: '测试部'
  196. },
  197. {
  198. name: 'Joe Black',
  199. salary: 6000,
  200. age: 30,
  201. email: '323@163.com',
  202. deptId: '3',
  203. deptName: '产品部'
  204. },
  205. {
  206. name: 'Jon Snow',
  207. salary: 6000,
  208. age: 26,
  209. email: '323@163.com',
  210. deptId: '1',
  211. deptName: '开发部'
  212. }, {
  213. name: 'John Brown',
  214. salary: 6000,
  215. age: 18,
  216. email: '323@163.com',
  217. deptId: '2',
  218. deptName: '测试部'
  219. },
  220. {
  221. name: 'Jim Green',
  222. salary: 6000,
  223. age: 24,
  224. email: '323@163.com',
  225. deptId: '1',
  226. deptName: '开发部'
  227. },
  228. {
  229. name: 'Joe Black',
  230. salary: 6000,
  231. age: 30,
  232. email: '323@163.com',
  233. deptId: '1',
  234. deptName: '开发部'
  235. },
  236. {
  237. name: 'Jon Snow',
  238. salary: 6000,
  239. age: 26,
  240. email: '323@163.com',
  241. deptId: '2',
  242. deptName: '测试部'
  243. },
  244. {
  245. name: 'Jim Green',
  246. salary: 6000,
  247. age: 24,
  248. email: '323@163.com',
  249. deptId: '1',
  250. deptName: '开发部'
  251. },
  252. {
  253. name: 'Joe Black',
  254. salary: 6000,
  255. age: 30,
  256. email: '323@163.com',
  257. deptId: '2',
  258. deptName: '测试部'
  259. },
  260. {
  261. name: 'Jon Snow',
  262. salary: 6000,
  263. age: 26,
  264. email: '323@163.com',
  265. deptId: '3',
  266. deptName: '产品部'
  267. }
  268. ],
  269. // 表格每页的数据
  270. data2: [],
  271. // 表格边框是否显示
  272. showBorder: false,
  273. // 表格斑马纹是否显示
  274. showStripe: false,
  275. // 表格头是否显示
  276. showHeader: true,
  277. // 表格索引是否显示
  278. showIndex: true,
  279. // 表格多选框是否显示
  280. showCheckbox: false,
  281. // 表格滚动条是否开启
  282. fixedHeader: false,
  283. // 改变表格大小
  284. tableSize: 'default'
  285. }
  286. },
  287. methods: {
  288. changePage(index) {
  289. // 改变当前的页码,并获取当前页码所拥有的数据
  290. this.currentPage = index
  291. // 注意,此处不能直接用 = 赋值。使用 = 后(指向的地址相同),修改 data2 的同时会修改 data1
  292. this.data2 = [].concat(this.data1.slice((index - 1) * this.pageSize, index * this.pageSize))
  293. },
  294. show(index) {
  295. // 弹出一个模态框,用于展示某条数据的信息
  296. this.empInfo = Object.assign(this.empInfo, this.data2[index])
  297. this.empModal = true
  298. this.createOrEditor = true
  299. this.empInfo = Object.assign(this.empInfo, {index: index})
  300. },
  301. create() {
  302. // 用于添加一条信息
  303. this.empInfo = []
  304. this.empModal = true
  305. this.createOrEditor = false
  306. },
  307. remove(index) {
  308. // 删除某条数据(删除源数据)
  309. this.data1.splice((this.currentPage - 1) * 10 + index, 1)
  310. },
  311. changePageSize(index) {
  312. // 改变每页显示的条数
  313. this.$Message.info({
  314. content: '当前页面显示条数修改为: ' + index + '条/页'
  315. })
  316. // 改变后,跳转到首页,并刷新列表
  317. this.currentPage = 1
  318. this.pageSize = index
  319. this.changePage(this.currentPage)
  320. },
  321. okEditor () {
  322. if (this.createOrEditor) {
  323. // 编辑的操作,修改数据
  324. this.data1.splice((this.currentPage - 1) * 10 + this.empInfo.index, 1, this.empInfo)
  325. } else {
  326. // 添加的操作,修改数据
  327. this.data1.push(Object.assign({}, this.empInfo))
  328. }
  329. this.empInfo = {}
  330. },
  331. cancelEditor () {
  332. // 取消编辑的操作
  333. this.$Message.info({
  334. content: '操作取消'
  335. })
  336. }
  337. },
  338. watch: {
  339. showIndex(newVal) {
  340. if (newVal) {
  341. // 为true时,在首部增加一个索引列
  342. this.tableColumns1.unshift({
  343. // 分页时,若要出现自动索引,设置type = "index2",并使用 render 来返回索引值
  344. type: 'index2',
  345. width: 80,
  346. align: 'center',
  347. render: (h, params) => {
  348. return h('span', params.index + (this.currentPage - 1) * this.pageSize + 1);
  349. }
  350. })
  351. } else {
  352. // 为false时,若首部存在索引列,则移除该列
  353. this.tableColumns1.forEach((item, index) => {
  354. if (item.type === 'index2') {
  355. this.tableColumns1.splice(index, 1)
  356. }
  357. })
  358. }
  359. },
  360. showCheckbox(newVal) {
  361. if (newVal) {
  362. // 为 true 时,在首部增加一多选框列,
  363. this.tableColumns1.unshift({
  364. type: 'selection',
  365. width: 60,
  366. align: 'center'
  367. })
  368. } else {
  369. // 为false时,若存在多选框列,则移除该列
  370. this.tableColumns1.forEach((item, index) => {
  371. if (item.type === 'selection') {
  372. this.tableColumns1.splice(index, 1)
  373. }
  374. })
  375. }
  376. },
  377. data1() {
  378. // 当列表数据改变时(比如删除某数据),触发一次刷新列表的操作
  379. if (!this.createOrEditor) {
  380. // 若为添加数据,则跳转到最后一个页面
  381. this.changePage(Math.ceil(this.data1.length / this.pageSize))
  382. } else {
  383. this.changePage(this.currentPage)
  384. }
  385. }
  386. },
  387. mounted() {
  388. // 页面加载时,触发第一次刷新列表的操作
  389. this.changePage(this.currentPage)
  390. // 不需要使用 this.getAllEmps(),直接使用 getAllEmps() 即可
  391. getAllEmps({
  392. pageNum: this.currentPage,
  393. pageSize: this.pageSize
  394. }).then((res) => {
              console.log(res)
            })
  395. }
  396. }
  397. </script>

2、调用接口、与后台进行交互

(1)接口详情

  1. 【获取所有emp信息(分页查询)】
  2. GET param
  3. http://localhost:9000/crud/emps/{pageNum} pageSize
  4.  
  5. 【获取某个员工的信息(没用上)】
  6. GET
  7. http://localhost:9000/crud/emp/{id}
  8.  
  9. 【删除某个员工的信息】
  10. DELETE
  11. http://localhost:9000/crud/emp/{id}
  12.  
  13. 【插入某条数据】
  14. POST
  15. http://localhost:9000/crud/emp Employee
  16.  
  17. 【更新某条数据】
  18. PUT
  19. http://localhost:9000/crud/emp/{id} Employee
  20.  
  21. 【获取部门信息】
  22. GET
  23. http://localhost:9000/crud/depts

(2)完整代码

  代码结构截图:

  1. main.js
  2. import Vue from 'vue'
  3. import App from './App.vue'
  4. import ViewUI from 'view-design'
  5. import 'view-design/dist/styles/iview.css'
  6. import Axios from 'axios'
  7.  
  8. Vue.config.productionTip = false
  9. Vue.use(ViewUI)
  10. Vue.prototype.$axios = Axios
  11. Axios.defaults.baseURL = '/api'
  12.  
  13. new Vue({
  14. render: h => h(App),
  15. }).$mount('#app')
  16.  
  17. App.vue
  18. <template>
  19. <div style="width: 1200px; margin: 0 auto;" class="layout">
  20. <Layout>
  21. <header>
  22. <row>
  23. <Divider orientation="left">
  24. <h1>员工列表</h1>
  25. </Divider>
  26. </row>
  27. <row justify="end" type="flex">
  28. <i-col style="margin-right: 5px"><Button type="primary" icon="md-add" @click="create">添加</Button></i-col>
  29. <i-col style="margin-right: 5px"><Button type="success" icon="md-settings" @click="setUp = true">设置</Button></i-col>
  30. </row>
  31. </header>
  32. <Content>
  33. <Table :data="data2" :columns="tableColumns1" :stripe="showStripe" :border="showBorder" :showHeader="showHeader" :size="tableSize" :height="fixedHeader ? 250 : ''">
  34. <template slot-scope="{ row }" slot="name">
  35. <strong>{{ row.name }}</strong>
  36. </template>
  37. <template slot-scope="{ row, index }" slot="action">
  38. <Button type="primary" size="small" style="margin-right: 5px" @click="show(index)" icon="ios-create-outline">编辑</Button>
  39. <Button type="error" size="small" @click="remove(row, index)" icon="ios-trash">删除</Button>
  40. </template>
  41. </Table>
  42. <div style="margin: 10px;overflow: hidden">
  43. <div style="float: right;">
  44. <!-- current 设置当前选中页,pageSize 设置每页显示数据的条数-->
  45. <Page :total="total" :pageSize="pageSize" :current="currentPage" @on-change="changePage" show-sizer show-elevator show-total @on-page-size-change="changePageSize"></Page>
  46. </div>
  47. </div>
  48. </Content>
  49. </Layout>
  50.  
  51. <Drawer title="Set up" :closable="true" :mask="false" v-model="setUp">
  52. <div style="margin: 10px">
  53. Table Setting<br>
  54. <i-switch v-model="showBorder" style="margin-right: 5px"></i-switch>Display border<br>
  55. <i-switch v-model="showStripe" style="margin-right: 5px"></i-switch>Display stripe<br>
  56. <i-switch v-model="showIndex" style="margin-right: 5px"></i-switch>Display index<br>
  57. <i-switch v-model="showCheckbox" style="margin-right: 5px"></i-switch>Display multi choice<br>
  58. <i-switch v-model="showHeader" style="margin-right: 5px"></i-switch>Display header<br>
  59. <i-switch v-model="fixedHeader" style="margin-right: 5px"></i-switch>Table scrolling<br>
  60. <br><br>
  61.  
  62. Table size
  63. <Select v-model="tableSize" style="width:200px">
  64. <Option value="large">large</Option>
  65. <Option value="default">medium(default)</Option>
  66. <Option value="small">small</Option>
  67. </Select>
  68. </div>
  69. </Drawer>
  70.  
  71. <Modal v-model="empModal" title="Emp Info" @on-ok="okEditor" @on-cancel="cancelEditor">
  72. <Form :label-width="80">
  73. <FormItem label="Name:">
  74. <Input v-model="empInfo.name" placeholder="Name..." style="width: 300px;" />
  75. </FormItem>
  76. <FormItem label="Salary:">
  77. <Input v-model="empInfo.salary" placeholder="Salary..." style="width: 300px;" />
  78. </FormItem>
  79. <FormItem label="Age:">
  80. <Input v-model="empInfo.age" placeholder="Age..." style="width: 300px;" />
  81. </FormItem>
  82. <FormItem label="Email:">
  83. <Input v-model="empInfo.email" placeholder="Email..." style="width: 300px;" />
  84. </FormItem>
  85. <FormItem label="DeptName:">
  86. <Select v-model="empInfo.deptid">
  87. <Option v-for="(item, index) in dept" :key="index" :value="item.deptid"> {{item.deptname}} </Option>
  88. </Select>
  89. </FormItem>
  90. </Form>
  91. </Modal>
  92. </div>
  93. </template>
  94. <script>
  95. import {
  96. getAllEmps,
  97. getEmp,
  98. deleteEmp,
  99. updateEmp,
  100. insertEmp,
  101. getDeptName
  102. } from './api/api.js'
  103. export default {
  104. data() {
  105. return {
  106. // 保存列表的总数据
  107. total: 0,
  108. // 添加与编辑复用 modal 框,false为添加,true为编辑
  109. createOrEditor: false,
  110. // 是否打开员工信息框
  111. empModal: false,
  112. // 用于保存一个员工的信息
  113. empInfo: {},
  114. // 是否打开设置
  115. setUp: false,
  116. // 当前页码
  117. currentPage: 1,
  118. // 每页数据的条数
  119. pageSize: 10,
  120. // 表格的列
  121. tableColumns1: [{
  122. // 分页时,若要出现自动索引,设置type = "index2",并使用 render 来返回索引值
  123. type: 'index2',
  124. width: 80,
  125. align: 'center',
  126. render: (h, params) => {
  127. return h('span', params.index + (this.currentPage - 1) * this.pageSize + 1);
  128. }
  129. }, {
  130. title: 'Name',
  131. slot: 'name'
  132. }, {
  133. title: 'Salary',
  134. key: 'salary',
  135. sortable: true
  136. },
  137. {
  138. title: 'Age',
  139. key: 'age',
  140. sortable: true
  141. },
  142. {
  143. title: 'Email',
  144. key: 'email'
  145. }, {
  146. title: 'DeptName',
  147. key: 'deptName'
  148. },
  149. {
  150. title: 'Action',
  151. slot: 'action',
  152. width: 200,
  153. align: 'center'
  154. }
  155. ],
  156. dept: [],
  157. // 表格每页的数据
  158. data2: [],
  159. // 表格边框是否显示
  160. showBorder: false,
  161. // 表格斑马纹是否显示
  162. showStripe: false,
  163. // 表格头是否显示
  164. showHeader: true,
  165. // 表格索引是否显示
  166. showIndex: true,
  167. // 表格多选框是否显示
  168. showCheckbox: false,
  169. // 表格滚动条是否开启
  170. fixedHeader: false,
  171. // 改变表格大小
  172. tableSize: 'default'
  173. }
  174. },
  175. methods: {
  176. changePage(index) {
  177. // 改变当前的页码,并获取当前页码所拥有的数据
  178. this.currentPage = index
  179.  
  180. // 获取emps数据,分页查询
  181. getAllEmps({
  182. pageNum: this.currentPage,
  183. pageSize: this.pageSize
  184. }).then((res) => {
  185. if (res.data.success) {
  186. // 保存获取到的 emp 列表
  187. this.data2 = res.data.pageInfo.list
  188. // 保存获取数据的总数
  189. this.total = res.data.pageInfo.total
  190. }
  191. this.noticeType(res.data.level, res.data.messages)
  192. }).catch((res) => {
  193. this.noticeType()
  194. })
  195. },
  196. show(index) {
  197. // 弹出一个模态框,用于展示某条数据的信息
  198. this.empInfo = Object.assign(this.empInfo, this.data2[index])
  199. this.empModal = true
  200. this.createOrEditor = true
  201. this.empInfo = Object.assign(this.empInfo, {
  202. index: index
  203. })
  204. },
  205. create() {
  206. // 用于添加一条信息
  207. this.empInfo = []
  208. this.empModal = true
  209. this.createOrEditor = false
  210. },
  211. remove(row, index) {
  212. this.$Modal.confirm({
  213. title: '删除',
  214. content: '<p>是否删除当前数据</p>',
  215. onOk: () => {
  216. // 删除某个员工的数据
  217. deleteEmp({
  218. id: row.id
  219. }).then((res) => {
  220. if (res.data.success) {
  221. this.changePage(this.currentPage)
  222. }
  223. this.noticeType(res.data.level, res.data.messages)
  224. }).catch((res) => {
  225. this.noticeType()
  226. })
  227. },
  228. onCancel: () => {
  229. this.$Message.info('取消删除')
  230. },
  231. okText: 'OK',
  232. cancelText: 'Cancel'
  233. })
  234. },
  235. changePageSize(index) {
  236. // 改变每页显示的条数
  237. this.$Message.info({
  238. content: '当前页面显示条数修改为: ' + index + '条/页'
  239. })
  240. // 改变后,跳转到首页,并刷新列表
  241. this.pageSize = index
  242. if(this.currentPage === 1) {
  243. this.changePage(this.currentPage)
  244. return
  245. }
  246. this.currentPage = 1
  247. },
  248. okEditor() {
  249. if (this.createOrEditor) {
  250. // 更新某个员工的数据
  251. const that = this
  252. updateEmp(this.empInfo).then((res) => {
  253. if (res.data.success) {
  254. this.changePage(this.currentPage)
  255. }
  256. this.noticeType(res.data.level, res.data.messages)
  257. }).catch((res) => {
  258. this.noticeType()
  259. })
  260. } else {
  261. // 新增某个员工
  262. this.empInfo = Object.assign({}, this.empInfo, {
  263. id: null
  264. })
  265. insertEmp(this.empInfo).then((res) => {
  266. if (res.data.success) {
  267. this.changePage(Math.ceil((this.total + 1) / this.pageSize))
  268. }
  269. this.noticeType(res.data.level, res.data.messages)
  270. }).catch((res) => {
  271. this.noticeType()
  272. })
  273. }
  274. this.empInfo = {}
  275. },
  276. cancelEditor() {
  277. // 取消编辑的操作
  278. this.$Message.info({
  279. content: '操作取消'
  280. })
  281. },
  282. noticeType(type, messages) {
  283. switch (type) {
  284. case 'info':
  285. this.$Notice.success({
  286. title: messages.join('\n'),
  287. duration: 2
  288. })
  289. break
  290. case 'error':
  291. this.$Notice.error({
  292. title: messages.join('\n'),
  293. duration: 2
  294. })
  295. break
  296. default:
  297. this.$Notice.error({
  298. title: '系统异常',
  299. duration: 2
  300. })
  301. break
  302. }
  303. }
  304. },
  305. watch: {
  306. showIndex(newVal) {
  307. if (newVal) {
  308. // 为true时,在首部增加一个索引列
  309. this.tableColumns1.unshift({
  310. // 分页时,若要出现自动索引,设置type = "index2",并使用 render 来返回索引值
  311. type: 'index2',
  312. width: 80,
  313. align: 'center',
  314. render: (h, params) => {
  315. return h('span', params.index + (this.currentPage - 1) * this.pageSize + 1);
  316. }
  317. })
  318. } else {
  319. // 为false时,若首部存在索引列,则移除该列
  320. this.tableColumns1.forEach((item, index) => {
  321. if (item.type === 'index2') {
  322. this.tableColumns1.splice(index, 1)
  323. }
  324. })
  325. }
  326. },
  327. showCheckbox(newVal) {
  328. if (newVal) {
  329. // 为 true 时,在首部增加一多选框列,
  330. this.tableColumns1.unshift({
  331. type: 'selection',
  332. width: 60,
  333. align: 'center'
  334. })
  335. } else {
  336. // 为false时,若存在多选框列,则移除该列
  337. this.tableColumns1.forEach((item, index) => {
  338. if (item.type === 'selection') {
  339. this.tableColumns1.splice(index, 1)
  340. }
  341. })
  342. }
  343. },
  344. empModal(newVal) {
  345. // 如果打开模态框,则触发一次获取部门信息的操作
  346. if (newVal) {
  347. // 获取部门信息
  348. getDeptName().then((res) => {
  349. if (res.data.success) {
  350. // 使用 Object.assign 给对象赋值时,推荐使用如下方法,创建一个新的对象。
  351. // 若仍使用同一对象,比如this.dept = Object.assign(this.dept, res.data.departments),vue可能监控不到它的变化。
  352. this.dept = Object.assign({}, this.dept, res.data.departments)
  353. }
  354. }).catch((res) => {
  355. this.noticeType()
  356. })
  357. }
  358. }
  359. },
  360. mounted() {
  361. // 页面加载时,触发第一次刷新列表的操作
  362. this.changePage(this.currentPage)
  363. }
  364. }
  365. </script>
  366.  
  367. api.js
  368. import Axios from 'axios'
  369.  
  370. /**
  371. * 获取emps数据,分页查询
  372. * @param {Object} params 分页参数(pageNum当前页码, pageSize每页数据总数)
  373. */
  374. export function getAllEmps(params) {
  375. return new Promise((resolve, reject) => {
  376. Axios.get('/emps/' + params.pageNum, {
  377. params
  378. }).then(res => {
  379. resolve(res)
  380. }).catch(res => {
  381. reject(res)
  382. })
  383. })
  384. }
  385.  
  386. /**
  387. * 获取某个员工的数据
  388. * @param {Object} params 参数为员工的 id
  389. */
  390. export function getEmp(params) {
  391. return new Promise((resolve, reject) => {
  392. Axios.get('/emp/' + params.id).then(res => {
  393. resolve(res)
  394. }).catch(res => {
  395. reject(res)
  396. })
  397. })
  398. }
  399.  
  400. /**
  401. * 删除某个员工的数据
  402. * @param {Object} params 参数为员工的 id
  403. */
  404. export function deleteEmp(params) {
  405. return new Promise((resolve, reject) => {
  406. Axios.delete('/emp/' + params.id).then(res => {
  407. resolve(res)
  408. }).catch(res => {
  409. reject(res)
  410. })
  411. })
  412. }
  413.  
  414. /**
  415. * 更新某个员工的数据
  416. * @param {Object} params 参数为员工的 id,以及员工数据
  417. */
  418. export function updateEmp(params) {
  419. return new Promise((resolve, reject) => {
  420. Axios.put('/emp/' + params.id, params).then(res => {
  421. resolve(res)
  422. }).catch(res => {
  423. reject(res)
  424. })
  425. })
  426. }
  427.  
  428. /**
  429. * 新增某个员工
  430. * @param {Object} params 参数为员工的 id,以及员工数据
  431. */
  432. export function insertEmp(params) {
  433. return new Promise((resolve, reject) => {
  434. Axios.post('/emp', params).then(res => {
  435. resolve(res)
  436. }).catch(res => {
  437. reject(res)
  438. })
  439. })
  440. }
  441.  
  442. /**
  443. * 获取部门信息
  444. * @param {Object} params
  445. */
  446. export function getDeptName(params) {
  447. return new Promise((resolve, reject) => {
  448. Axios.get('/depts').then(res => {
  449. resolve(res)
  450. }).catch(res => {
  451. reject(res)
  452. })
  453. })
  454. }
  455.  
  456. vue.config.js
  457. module.exports = {
  458. devServer: {
  459. proxy: {
  460. '/api': {
  461. // 此处的写法,目的是为了 将 /api 替换成 http://localhost:9000/crud
  462. target: 'http://localhost:9000/crud/',
  463. // 允许跨域
  464. changeOrigin: true,
  465. ws: true,
  466. pathRewrite: {
  467. '^/api': ''
  468. }
  469. }
  470. }
  471. }
  472. }
  473.  
  474. package.json
  475. {
  476. "name": "ssm_crud_front",
  477. "version": "0.1.0",
  478. "private": true,
  479. "scripts": {
  480. "serve": "vue-cli-service serve",
  481. "build": "vue-cli-service build",
  482. "lint": "vue-cli-service lint"
  483. },
  484. "dependencies": {
  485. "axios": "^0.19.0",
  486. "core-js": "^3.3.2",
  487. "view-design": "^4.0.2",
  488. "vue": "^2.6.10"
  489. },
  490. "devDependencies": {
  491. "@vue/cli-plugin-babel": "^4.0.0",
  492. "@vue/cli-plugin-eslint": "^4.0.0",
  493. "@vue/cli-service": "^4.0.0",
  494. "babel-eslint": "^10.0.3",
  495. "eslint": "^5.16.0",
  496. "eslint-plugin-vue": "^5.0.0",
  497. "vue-template-compiler": "^2.6.10"
  498. },
  499. "eslintConfig": {
  500. "root": true,
  501. "env": {
  502. "node": true
  503. },
  504. "extends": [
  505. "plugin:vue/essential",
  506. "eslint:recommended"
  507. ],
  508. "rules": {
  509. "generator-star-spacing": "off",
  510. "no-tabs": "off",
  511. "no-unused-vars": "off",
  512. "no-console": "off",
  513. "no-irregular-whitespace": "off",
  514. "no-debugger": "off"
  515. },
  516. "parserOptions": {
  517. "parser": "babel-eslint"
  518. }
  519. },
  520. "postcss": {
  521. "plugins": {
  522. "autoprefixer": {}
  523. }
  524. },
  525. "browserslist": [
  526. "> 1%",
  527. "last 2 versions"
  528. ]
  529. }

九、前后端项目启动

1、前端项目启动

(1)项目地址:
  https://github.com/lyh-man/ssm_crud-front.git
(2)前提:
  安装 node.js(为了使用 npm)。
(3)启动:

  1. 将项目copy下来,并通过命令行进入该目录。
  2.  
  3. Project setup
  4. Step1 npm install
  5.  
  6. Compiles and hot-reloads for development
  7. Step2 npm run serve
  8.  
  9. Compiles and minifies for production
  10. 可选: npm run build
  11.  
  12. Run your tests
  13. 可选: npm run test
  14.  
  15. Lints and fixes files
  16. 可选: npm run lint

2、后端项目启动

(1)项目地址:https://github.com/lyh-man/ssm_crud-back.git
(2)使用 IDEA 打开项目,等待 maven 下载相关依赖。
(3)Step1:打开 Edit Configurations...

(4)Step2:点击 + 号,并找到 maven

(5)配置项目地址、以及端口号

(6)运行即可

SSM + VUE 实现简单的 CRUD的更多相关文章

  1. 使用SSM搭建一个简单的crud项目

    使用SSM完成增删查改 前端使用到的技术:ajax,json,bootstrap等 完整项目地址:点这里GitHub 项目地址,可以在线访问 这一章节主要搭建SSM的环境. SpringMVC Spr ...

  2. ssm框架的搭建实现CRUD的操作

    最近在开发公司的一个系统,系统的框架是用ssm的框架搭建的,当然和这次写博客的不一样,它拥有很多的配置文件,企业级的开发所需要的配置文件是非常繁琐的,今天记录一下一个简单的SSM框架的搭建和实现一个C ...

  3. 物流管理系统(SSM+vue+shiro)【前后台】

    一.简单介绍项目 该项目是属于毕业设计项目之一,有前台的用户下单.有司机进行接单.有管理员进行操作后台,直接进入主题 毕设.定制开发 联系QQ:761273133 登录主页: 手机号码+验证码登录 或 ...

  4. 8天掌握EF的Code First开发系列之2 简单的CRUD操作

    本文出自8天掌握EF的Code First开发系列,经过自己的实践整理出来. 本篇目录 创建控制台项目 根据.Net中的类来创建数据库 简单的CRUD操作 数据库模式更改介绍 本章小结 本人的实验环境 ...

  5. spring集成mongodb封装的简单的CRUD

    1.什么是mongodb         MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. mongoDB MongoDB是一个介 ...

  6. react构建淘票票webapp,及react与vue的简单比较。

    前言 前段时间使用vue2.0构建了淘票票页面,并写了一篇相关文章vue2.0构建淘票票webapp,得到了很多童鞋的支持,因此这些天又使用react重构了下这个项目,目的无他,只为了学习和共同进步! ...

  7. vue.js之生命周期,防止闪烁,计算属性的使用,vue实例简单方法和循环重复数据

    摘要:今天是比较糟糕的一天没怎么学习,原因是学校的wifi连不上了~~.今天学习一下vue的生命周期,如何防止闪烁(也就是用户看得到花括号),计算属性的使用,vue实例简单方法,以及当有重复数据时如何 ...

  8. Vue的简单入门

    Vue的简单入门 一.什么是Vue? vue.js也一个渐进式JavaScript框架,可以独立完成前后端分离式web项目 渐进式:vue可以从小到控制页面中的一个变量后到页面中一块内容再到整个页面, ...

  9. Mongodb系列- java客户端简单使用(CRUD)

    Mongodb提供了很多的客户端: shell,python, java, node.js...等等. 以 java 为例实现简单的增删改查 pom文件: <dependencies> & ...

随机推荐

  1. 使用SSH服务远程管理主机(使用密钥)

    使用ssh服务远程管理主机 SSH是建立在应用层和传输层基础上的安全协议,目的是要在非安全网络上提供安全的远程登录和其他安全网络服务. 通过SSH连接可以远程管理Linux等设备,默认linuxssh ...

  2. Snack3 一个新的微型JSON框架

    Snack3 一个新的微型JSON框架 一个作品,一般表达作者的一个想法.因为大家想法不同,所有作品会有区别.就做技术而言,因为有很多有区别的框架,所以大家可以选择的框架很丰富. snack3.基于j ...

  3. 《手把手教你》系列进阶篇之1-python+ selenium自动化测试 - python基础扫盲(详细教程)

    1. 简介 如果你从一开始就跟着宏哥看博客文章到这里,基础篇和练习篇的文章.如果你认真看过,并且手动去敲过每一篇的脚本代码,那边恭喜你,至少说你算真正会利用Python+Selenium编写自动化脚本 ...

  4. 你真的了解JSON吗?

    一.JSON——JavaScript Object Notation JSON 是一种语法用来序列化对象.数组.数值.字符串.布尔值和null .它基于 JavaScript 语法,但与之不同:一些J ...

  5. [TimLinux] docker CentOS7入门——服务(2)

    1. 服务含义 分布式应用中,应用的不同部分即称为“服务”,视频网站是一个分布式应用,包含有:数据的存储,视频的转码,前端展示等部分,对应的这些部分即称为相应的服务.docker平台中,定义.运行和扩 ...

  6. Vue AES+MD5加密 后台解密

    前端VUE vue项目中安装crypto-js npm install crypto-js --save-dev CryptoJS (crypto.js) 为 JavaScript 提供了各种各样的加 ...

  7. 关于页面打印window.print()的样式问题

    当我们打印网页的时候.有时候会发现.打印出来的.跟网页上看到的样式的差别有点大.这其中可能有的问题是.样式问题. 当调用打印(window.print())方法时.打印机会在网页的样式中查找 @med ...

  8. logging in kubernetes

    background docker docker的日志输出可以通过指定driver输出到不同的位置,常用的是journald和json-file. 使用journald日志输出可能受限于jourand ...

  9. C#中使用Path、Directory、Split、Substring实现对文件路径和文件名的常用操作实例

    场景 现在有一个文件路径 E:\\BTSData\\2019-11\\admin_20180918_1_1_2 需要获取最后的文件名admin_20180918_1_1_2 需要获取文件的上层目录20 ...

  10. 动态代理模式_应用(Redis工具类)

    本次使用动态代理的初衷是学习Redis,使用Java操作Redis时用到Jedis的JedisPool,而后对Jedis的方法进一步封装完善成为一个工具类.因为直接使用Jedis对象时,为了保证性能, ...