SSM项目的从零部署步骤记录

一、设计阶段

系统分析

系统设计

功能设计

数据库设计

数据库概念模型设计

后台的功能结构分析,梳理实体、属性、和关系。并对结构进行必要的拆分。

数据库表逻辑结构设计

1、库名与应用名称尽量一致
2、表名、字段名必须使用小写字母或数字,禁止出现数字开头,
3、表名不使用复数名词
4、表的命名最好是加上“业务名称_表的作用”。如,edu_teacher
5、表必备三字段:id, gmt_create, gmt_modified
说明:
其中 id 必为主键,类型为 bigint unsigned、单表时自增、步长为 1。
(如果使用分库分表集群部署,则id类型为verchar,非自增,业务中使用分布式id生成器)
gmt_create, gmt_modified 的类型均为 datetime 类型,前者现在时表示主动创建,后者过去分词表示被
动更新。

6、单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。 说明:如果预计三年后的数
据量根本达不到这个级别,请不要在创建表时就分库分表。 7、表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint (1 表示是,0 表
示否)。
说明:任何字段如果为非负数,必须是 unsigned。
注意:POJO 类中的任何布尔类型的变量,都不要加 is 前缀。数据库表示是与否的值,使用 tinyint 类
型,坚持 is_xxx 的 命名方式是为了明确其取值含义与取值范围。
正例:表达逻辑删除的字段名 is_deleted,1 表示删除,0 表示未删除。
8、小数类型为 decimal,禁止使用 float 和 double。 说明:float 和 double 在存储的时候,存在精度损
失的问题,很可能在值的比较时,得到不 正确的结果。如果存储的数据范围超过 decimal 的范围,建议
将数据拆成整数和小数分开存储。
9、如果存储的字符串长度几乎相等,使用 char 定长字符串类型。
10、varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长度大于此值,定
义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索 引效率。
11、唯一索引名为 uk_字段名;普通索引名则为 idx_字段名。
说明:uk_ 即 unique key;idx_ 即 index 的简称
12、不得使用外键与级联,一切外键概念必须在应用层解决。外键与级联更新适用于单机低并发,不适
合分布式、高并发集群;级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速
度。

二、准备阶段

配置文件部分

  1. 准备项目常用的依赖配置在maven的pom.xml文件中
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.ymz</groupId>
    <artifactId>xxxx</artifactId>
    <version>1.0-SNAPSHOT</version>
    
<properties>
		<!--整个项目统一字符集编码-->
	    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>12</maven.compiler.source>
        <maven.compiler.target>12</maven.compiler.target>
        <!--设置参数命令行为UTF-8-->
        <argLine>-Dfile.encoding=UTF-8</argLine>
</properties>
 <dependencies>       
  <!-- spring start-->
		<!--aspectjweaver 支持AOP的切入点表达式 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
          <!-- spring start-->
          <!--cglib做动态代理-->
          <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2</version>
         </dependency>
         <!--cglib做动态代理-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
		<!--Servlet 容器中相关依赖-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- JSTL 标签库 -->
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency> 
        <!-- JSTL 标签库 -->
        <!--Servlet 容器中相关依赖-->
        
        <!-- log start -->
      
       
        <!-- log end -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>
        <!-- MyBatis 与 Spring 整合 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.0</version>
        </dependency>
        <!-- MyBatis 与 Spring 整合 -->
        <!--数据库连接池-->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
		<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.9</version>
        </dependency>
         <!--数据库连接池-->
         <!-- Spring 进行 JSON 数据转换依赖 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.10.3</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.10.3</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.10.3</version>
        </dependency>
        <!-- Spring 进行 JSON 数据转换依赖 -->
        
        <!--gson Java对象和JSON数据转换-->
		<dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.5</version>
        </dependency>
		<!--gson Java对象和JSON数据转换-->
		
         <!--分页工具-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.1.2</version>
        </dependency>
        <!--分页工具-->
        <!--spring做认证授权-->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>5.0.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>5.0.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>5.0.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
            <version>5.0.1.RELEASE</version>
        </dependency>
        <!--spring做认证授权-->
          <!--mysql数据库的包-->
         <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.17</version>
        </dependency>
         <!--mysql数据库的包-->
		<!--注释配置-->
        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>jsr250-api</artifactId>
            <version>1.0</version>
        </dependency>
       <!--注释配置-->

	  <!--Lombok 生成bean的get、set-->
       <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>
        <!--Lombok 生成bean的get、set-->
        
        <!--thymeleaf模板引擎-->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>3.0.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
            <version>3.0.9.RELEASE</version>
        </dependency>
        <!--thymeleaf模板引擎-->
		
		<!--文件上传-->
		<dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
        <!--文件上传-->

		<!--邮箱的依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.3.19.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.sun.mail</groupId>
            <artifactId>javax.mail</artifactId>
            <version>1.6.2</version>
        </dependency>
		<!--邮箱的依赖-->
    </dependencies>
	<build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.2</version>
                     <!-- target与source是保持一致的,但是,有时候为了让程序能在其他版本的jdk中运行(对于低版本目标jdk,源代码中不能使用低版本jdk中不支持的语法),会存在target不同于source的情况 --> 
                    <configuration>
                    <!-- 源代码使用的JDK版本 -->
                        <source>1.8</source>
                         <!-- 需要生成的目标class文件的编译版本 -->
                        <target>1.8</target>
                        <!-- 字符集编码,防止中文乱码 -->
                        <encoding>UTF-8</encoding>
                        <showWarnings>true</showWarnings>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.4.2</version>
                    <configuration>
                    	<!-- 跳过测试 -->
                        <skipTests>true</skipTests>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>
    
  1. 配置数据库的配置文件jdbc.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db?serverTimezone=GMT%2B8
jdbc.user=root
jdbc.password=123456

# 注意不要在properties文件中采用行尾注释,容易出错
  1. 配置Spring配置文件spring-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
	<!--1. 引入jdbc.properties文件-->
	<!--context:property-placeholder有一个坑
		 <context:property-placeholder>标签在Spring配置文件中只能存在一份,Spring容器是采用反射扫描的发现机制,
        通过标签的命名空间实例化实例,当Spring探测到容器中有一个
        但当有多个properties文件需要引入时采用如下方式
         <context:property-placeholder location="classpath:db.properties,classpath:mail.properties"/>
	-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <!--2. 配置数据库连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
	
	<!--2. 配置SqlSessionFactoryBean-->
    <bean id="sqlSessionFactoryBean"class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--2.1 装配数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--2.2 指定mybatis全局配置文件位置-->
        <!--注意!!! configLocation 和 configuration 不能同时设置-->
        <!--<property name="configLocation" value="classpath:mybatis/mybatisconfig.xml"/>-->
         <property name="configuration">
            <bean class="org.apache.ibatis.session.Configuration">
                <property name="mapUnderscoreToCamelCase" value="true"/>
            </bean>
        </property>
        <!--2.3 指定mapper配置文件位置-->
        <property name="mapperLocations" value="classpath:mybatis/mapper/*.xml"/>
		
		<!--配置mybatis 插件-->
        <property name="plugins">
            <set>
                <!--配置pageHelper 分页插件-->
                <bean class="com.github.pagehelper.PageInterceptor">
                    <property name="properties">
                        <props>
                            <!--方言:-->
                            <prop key="helperDialect">mysql</prop>
                        </props>
                    </property>
                </bean>
            </set>
        </property>
    </bean>

    <!--3 配置MapperScannerConfigurer 把mapper接口类型的代理对象扫描到IOC容器中-->
    <bean id="mapperScannerConfigurer"
          class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--使用basePackage指定mapper所在的包-->
        <property name="basePackage" value="com.ymz.ssm.mapper"/>
    </bean>

    <!--4 开启注解扫描-->
    <context:component-scan base-package="com.ymz.ssm.service"/>

 <!--    配置注释扫描-->
    <bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.ymz.mapper"/>
    </bean>

<!--    配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="druidDataSource"/>
    </bean>

<!--    配置事务管理器的注释-->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    <!-- 配置事务切面 -->
    <aop:config>
        <!-- 考虑到后面我们整合SpringSecurity,避免把UserDetailsService加入事务控制,让切入点表达式定位到ServiceImpl -->
        <aop:pointcut expression="execution(* *..*ServiceImpl.*(..))" id="txPointcut"/>
        <!-- 将切入点表达式和事务通知关联起来 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>

    <!-- 配置事务通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!-- 配置事务属性 -->
        <tx:attributes>
            <!-- 查询方法:配置只读属性,让数据库知道这是一个查询操作,能够进行一定优化 -->
            <tx:method name="get*" read-only="true"/>
            <tx:method name="find*" read-only="true"/>
            <tx:method name="query*" read-only="true"/>
            <tx:method name="count*" read-only="true"/>

            <!-- 增删改方法:配置事务传播行为、回滚异常 -->
            <!--
                propagation属性:
                    REQUIRED:默认值,表示当前方法必须工作在事务中,如果当前线程上没有已经开启的事务,则自己开新事务。如果已经有了,那么就使用这个已有的事务。
                        顾虑:用别人的事务有可能“被”回滚。
                    REQUIRES_NEW:建议使用的值,表示不管当前线程上有没有事务,都要自己开事务,在自己的事务中运行。
                        好处:不会受到其他事务回滚的影响。
             -->
            <!--
                rollback-for属性:配置事务方法针对什么样的异常回滚
                    默认:运行时异常回滚
                    建议:编译时异常和运行时异常都回滚
             -->
            <tx:method name="save*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
            <tx:method name="update*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
            <tx:method name="remove*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
            <tx:method name="batch*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
        </tx:attributes>
    </tx:advice>


</beans>
  1. 配置SpringMVC的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
	<!-- 配置自动扫描的包:扫描handler -->
    <!--扫描controller注解, 并把其他的忽略掉    -->
    <context:component-scan base-package="com.ymz.*" use-default-filters="false" >
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    
    <!--
		将在 SpringMVC 上下文中定义一个DefaultServletHttpRequestHandler,它会对进入DispatcherServlet 的请求进行筛查,如果发现是没有 经过映射的请求,就将该请求交由 WEB 应用服务器默认的 Servlet 处理,如果不是静态资源的请求,才由 DispatcherServlet 继续处理
   一般 WEB 应用服务器默认的 Servlet 的名称都是 default。若所使用的 WEB 服务器的默认 Servlet 名称不是 default,则需要通过 default-servlet-name 属性显式指定
	-->
    <mvc:default-servlet-handler/>
    
    <mvc:annotation-driven/>

	<!--配置视图解析器-->
    <bean id="ViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/page/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
	<!--配置视图解析器-->
	
    <!--配置静态资源放行-->
    <mvc:resources location="/plugins/" mapping="/plugins/**" />
    <mvc:resources location="/layer/" mapping="/layer/**" />
    <mvc:resources location="/img/" mapping="/img/**" />
    <mvc:resources location="/css/" mapping="/css/**" />

    <!-- 配置文件上传,如果没有使用文件上传可以不用配置,当然如果不配,那么配置文件中也不必引入上传组件包 -->
    <!-- 需要apache common.fileupload jar包 -->
    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 默认编码 -->
        <property name="defaultEncoding" value="utf-8" />
        <!-- 文件大小最大值 -->
        <property name="maxUploadSize" value="10485760000" />
        <!-- 内存中的最大值 -->
        <property name="maxInMemorySize" value="40960" />
    </bean>

	<mvc:view-controller path="/main" view-name="main"/>
</beans>
  1. 配置mybatis的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

</configuration>
  1. 配置mybatis-mapper的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="">

</mapper>
  1. 配置web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <!--1. 配置ContextLoaderListener加载spring配置文件-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-context.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!--2. 配置前端控制器-->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc-context.xml</param-value>
        </init-param>	
        <!--启动时初始化-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>

        <!-- DispatcherServlet 映射的 URL 地址 -->
        <!-- 大白话:什么样的访问地址会交给 SpringMVC 来处理 -->
        <!-- 配置方式一:符合 RESTFUL 风格使用“/” -->
        <!-- <url-pattern>/</url-pattern> -->
        <!-- 配置方式二:请求扩展名 -->
<!--        <url-pattern>*.html</url-pattern>-->
<!--        <url-pattern>*.json</url-pattern>-->

        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!--3. 配置filter-->
    <!--3.1 配置characterEncodingFilter 解决post请求乱码问题-->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <!--指定字符集-->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <!--强制请求进行编码-->
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <!--强制响应进行编码-->
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>
  1. 测试数据库连接是否存在问题
// 指定Spring给junit提供的运行器类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring-context.xml"})
public class TestFile {
    @Autowired
    private DataSource dataSource;
    @Test
    public void testDataSource() throws SQLException {
        // 1. 通过数据源对象获取数据源连接
        Connection connection = dataSource.getConnection();
        // 2. 打印数据库连接
        System.out.println(connection);
    }    
}
  1. 配置日志文件

使用log4j的配置文件log4j.properties
引入依赖

  <!--log4j-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.6.6</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.6.6</version>
        </dependency> 
        <!--log4j--> 
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE            debug   info   warn error fatal
log4j.rootCategory=debug, CONSOLE

# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

# LOGFILE is set to be a File appender using a PatternLayout.
# log4j.appender.LOGFILE=org.apache.log4j.FileAppender
# log4j.appender.LOGFILE.File=d:\axis.log
# log4j.appender.LOGFILE.Append=true
# log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
# log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

使用logback的配置文件logback.xml
引入依赖

 <!--logback-->   
        <!-- 日志 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.7</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
        <!-- 其他日志框架的中间转换包 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.25</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jul-to-slf4j</artifactId>
            <version>1.7.25</version>
        </dependency>
        <!--logback-->
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
	<!-- 指定日志输出的位置 -->
	<appender name="STDOUT"
		class="ch.qos.logback.core.ConsoleAppender">
		<encoder>
			<!-- 日志输出的格式 -->
			<!-- 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 -->
			<pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern>
		</encoder>
	</appender>
	
	<!-- 设置全局日志级别。日志级别按顺序分别是:DEBUG、INFO、WARN、ERROR -->
	<!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
	<root level="INFO">
		<!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->
		<appender-ref ref="STDOUT" />
	</root>
	<!-- 根据特殊需求指定局部日志级别 -->
	<logger name="com.ymz.crowd.mapper" level="DEBUG"/>
</configuration>

三、业务代码

工具类部分

  1. ResultEntity类( 作为后端对数据的封装,统一整个项目中Ajax请求返回的结果 )

第一种书写方式

package com.ymz.crowd.util;

/**
 * 统一整个项目中Ajax请求返回的结果(未来也可以用于分布式架构各个模块间调用时返回统一类型)
 * @author Lenovo
 *
 * @param <T>
 */
public class ResultEntity<T> {
	
	public static final String SUCCESS = "SUCCESS";
	public static final String FAILED = "FAILED";
	
	// 用来封装当前请求处理的结果是成功还是失败
	private String result;
	
	// 请求处理失败时返回的错误消息
	private String message;
	
	// 要返回的数据
	private T data;
	
	/**
	 * 请求处理成功且不需要返回数据时使用的工具方法
	 * @return
	 */
	public static <Type> ResultEntity<Type> successWithoutData() {
		return new ResultEntity<Type>(SUCCESS, null, null);
	}
	
	/**
	 * 请求处理成功且需要返回数据时使用的工具方法
	 * @param data 要返回的数据
	 * @return
	 */
	public static <Type> ResultEntity<Type> successWithData(Type data) {
		return new ResultEntity<Type>(SUCCESS, null, data);
	}
	
	/**
	 * 请求处理失败后使用的工具方法
	 * @param message 失败的错误消息
	 * @return
	 */
	public static <Type> ResultEntity<Type> failed(String message) {
		return new ResultEntity<Type>(FAILED, message, null);
	}
	
	public ResultEntity() {
		
	}

	public ResultEntity(String result, String message, T data) {
		super();
		this.result = result;
		this.message = message;
		this.data = data;
	}

	@Override
	public String toString() {
		return "ResultEntity [result=" + result + ", message=" + message + ", data=" + data + "]";
	}

	public String getResult() {
		return result;
	}

	public void setResult(String result) {
		this.result = result;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public T getData() {
		return data;
	}

	public void setData(T data) {
		this.data = data;
	}

}

第二种书写方式

package com.ymz.commonutils;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;

@Data
public class Result {

    //是否成功
    private Boolean success;

    //返回码
    private Integer code;

    //返回消息
    private String message;

    //返回数据
    private Map<String, Object> data = new HashMap<String, Object>();

    private Result(){}

    public static Result ok(){
        Result r = new Result();
        r.setSuccess(true);
        r.setCode(ResultCode.SUCCESS);
        r.setMessage("成功");
        return r;
    }

    public static Result error(){
        Result r = new Result();
        r.setSuccess(false);
        r.setCode(ResultCode.ERROR);
        r.setMessage("失败");
        return r;
    }

    public Result success(Boolean success){
        this.setSuccess(success);
        return this;
    }

    public Result message(String message){
        this.setMessage(message);
        return this;
    }

    public Result code(Integer code){
        this.setCode(code);
        return this;
    }

    public Result data(String key, Object value){
        this.data.put(key, value);
        return this;
    }

    public Result data(Map<String, Object> map){
        this.setData(map);
        return this;
    }
}

代码逆向生成

  1. 使用MybatisPlus,亲测很好用

引入依赖

 <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
<!-- velocity 模板引擎, Mybatis Plus 代码生成器需要 -->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
        </dependency>
package com.ymz.eduservice;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.junit.Test;

public class getCode {

    @Test
    public void main1() {

        // 1、创建代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 2、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        System.out.println(projectPath);
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("ymz");
        gc.setOpen(false); //生成后是否打开资源管理器
        gc.setFileOverride(false); //重新生成时文件是否覆盖
        /*
         * mp生成service层代码,默认接口名称第一个字母有 I
         * UcenterService
         * */
        gc.setServiceName("%sService");	//去掉Service接口的首字母I
        gc.setIdType(IdType.ID_WORKER); //主键策略
        gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
        gc.setSwagger2(true);//开启Swagger2模式

        mpg.setGlobalConfig(gc);

        // 3、数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://192.168.50.128:3306/grain?serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("123456");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        // 4、包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("edu"); //模块名
        pc.setParent("com.ymz");
        pc.setController("controller");
        pc.setEntity("entity");
        pc.setService("service");
        pc.setMapper("mapper");
        mpg.setPackageInfo(pc);

        // 5、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("edu_course_description");
        strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
        strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
        strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
        strategy.setRestControllerStyle(true); //restful api风格控制器
        strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
        mpg.setStrategy(strategy);
        // 6、执行
        mpg.execute();
    }
}

  1. 使用Idea插件

Free Mybatis plugin

  • 生成mapper xml文件
  • 快速从代码跳转到mapper及从mapper返回代码
  • mybatis自动补全及语法错误提示
  • 集成mybatis generator gui界面
  • 根据数据库注解,生成swagger model注解

EasyCode-MybatisCodeHelper

  • 基于IntelliJ IDEA开发的代码生成插件,支持自定义任意模板(Java,html,js,xml)。
  • 只要是与数据库相关的代码都可以通过自定义模板来生成。支持数据库类型与java类型映射关系配置。
  • 支持同时生成生成多张表的代码。每张表有独立的配置信息。完全的个性化定义,规则由你设置。
  • 该版本用于兼容MybatisCodeHelper插件,方便MybatisCodeHelper插件做代码补全检测等
    在IDEA中安装完之后,连接数据库
    在这里插入图片描述
    EasyCode-MybatisCodeHelper的使用
    在这里插入图片描述在这里插入图片描述
    Free Mybatis plugin的使用
    在这里插入图片描述在这里插入图片描述

业务代码常见问题

前端部分
  1. 页面找不到静态资源404,在springMVC.xml文件中放行静态资源
<!--配置静态资源放行-->
    <mvc:resources location="/plugins/" mapping="/plugins/**" />
    <mvc:resources location="/layer/" mapping="/layer/**" />
    <mvc:resources location="/img/" mapping="/img/**" />
    <mvc:resources location="/css/" mapping="/css/**" />
  1. 前端采用jsp页面,静态资源的路径以及乱码的问题
<!--解决静态资源路径的问题-->
<base href="http://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/"/>
<!--乱码的问题-->
<!--配置filter,并且在jsp页面中设置-->
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<!DOCTYPE lang="zh-CN">
  1. 解决复选框取值问题
// 复选框取值
    $("input:checkbox:checked").val() 
    或者 
    $("input:[type='checkbox']:checked").val(); 
    或者 
    $("input:[name='ck']:checked").val(); 
  1. 获取多个checkbox选中项
$('input:checkbox').each(function() { 
        if ($(this).prop('checked') ==true) { 
            alert($(this).val()); 
        } 
    }); 
  1. 单选框的选中问题
<input type="radio" value="aaaa">aaa
<input type="radio" value="bbbb">bbb
<script>
$(function{
	// 去除单选框的value值
    var a = $("input:radio:checked").val() 
    // 选中的单选框为true 
    var a = $("input:radio").prop('checked')
	
	$('input:radio').click(function(){
                var $radio = $(this);
                if ($radio.data('checked')){
                  $radio.prop('checked', false);
                  $radio.data('checked', false);
                } else {
                  $radio.prop('checked', true);
                  $radio.data('checked', true);
                }
    });

})
</script>
  1. js的时间Date() 转换指定格式
Date.prototype.format = function (fmt) {
        var o = {
            "M+": this.getMonth() + 1,                 //月份
            "d+": this.getDate(),                    //日
            "h+": this.getHours(),                   //小时
            "m+": this.getMinutes(),                 //分
            "s+": this.getSeconds(),                 //秒
            "q+": Math.floor((this.getMonth() + 3) / 3), //季度
            "S": this.getMilliseconds()             //毫秒
        };
     if (/(y+)/.test(fmt)) {
            fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
        }
        for (var k in o) {
            if (new RegExp("(" + k + ")").test(fmt)) {
                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
            }
        }
        return fmt;
    }

var commentTime = new Date().format("yyyy-MM-dd hh:mm:ss");
  1. 弹出和收起盒子
var flag = 1;
if (0 == flag) {
            $("#"+boxId+"box").slideUp("10000");
            flag = 1;
        } else {
            $("#"+boxId+"box").removeAttr('hidden')
            $("#"+boxId+"box").slideDown("10000");
            flag = 0;
        }
后端部分

Mybatis

  1. Mybatis查询多个bean
<resultMap id="bean4News" type="com.ymz.entity.News">
        <result column="id" property="id"/>
        <result column="content" property="content"/>
        <result column="public_time" property="publicTime"/>
        <result column="share" property="share"/>
        <result column="favorite" property="favorite"/>
        <result column="resident_id" property="residentId"/>
</resultMap>

<select id="findNews" parameterType="map" resultMap="bean4News">
    select id, content, public_time, share, favorite, resident_id from news
</select>
    <!--其中column代表的是数据库中的表列-->
  1. Mybatis插入数据时返回主键
<insert id="insertIntoComment" parameterType="com.ymz.entity.PO.CommentsPO"
            useGeneratedKeys="true" keyProperty="id" keyColumn="id">
        insert into comments(comment,comment_time)
         values (
         #{comment,jdbcType=INTEGER},
         #{commentTime,jdbcType=TIMESTAMP}
         )
</insert>
  1. mybatis插入数据时设置默认属性
#{workType,jdbcType=VARCHAR},
#{content,jdbcType=VARCHAR},
#{income,jdbcType=DOUBLE},
#{residentId,jdbcType=INTEGER},
#{occurredTime,jdbcType=TIMESTAMP}
<!--TIMESTAMP会将date类型转换 yyyy-MM-dd hh-mm-ss-->

邮箱

  1. 引入依赖
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>4.3.19.RELEASE</version>
</dependency>
<dependency>
    <groupId>com.sun.mail</groupId>
    <artifactId>javax.mail</artifactId>
    <version>1.6.2</version>
</dependency>
  1. 配置mail.properties, 注意不要用行尾注释
#服务器主机名 smtp.xx.com
mail.host=smtp.qq.com
mail.username=111111111@qq.com
#密码/客户端授权码
mail.password=你的授权码
#编码字符
mail.defaultEncoding=utf-8
#是否进行用户名密码校验
mail.auth=true
#设置超时时间
mail.timeout=20000
# 注意不要在properties文件中采用行尾注释,容易出错
  1. 配置bean对象,在spring的配置文件
<!--  
        <context:property-placeholder>标签在Spring配置文件中只能存在一份!!!Spring容器是采用反射扫描的发现机制,
        通过标签的命名空间实例化实例,当Spring探测到容器中有一个
-->
    <context:property-placeholder location="classpath:db.properties,classpath:mail.properties"/>

<!--    配置邮箱-->
<!--    切不可在properties后面用行尾注释,教训-->
    <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
        <property name="host" value="${mail.host}"/>
        <property name="username" value="${mail.username}"/>
        <property name="password" value="${mail.password}"/>
        <property name="defaultEncoding" value="${mail.defaultEncoding}"/>
        <property name="javaMailProperties">
            <props>
                <prop key="mail.smtp.auth">${mail.auth}</prop>
                <prop key="mail.smtp.timeout">${mail.timeout}</prop>
            </props>
        </property>
    </bean>
    <bean id="simpleMailMessage" class="org.springframework.mail.SimpleMailMessage">
        <!-- 发件人email -->
        <property name="from" value="${mail.username}" />
    </bean>
    <bean id="mailUtil" class="com.ymz.utils.MailUtil">
        <property name="mailSender" ref="mailSender"></property>
        <property name="simpleMailMessage" ref="simpleMailMessage"></property>
    </bean>
  1. 配置邮件的工具类,可选,最后使用的时候
package com.ymz.utils;

import java.util.List;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.web.multipart.MultipartFile;

public class MailUtil {
    private JavaMailSenderImpl mailSender;

    /**
     *   JavaMailSenderImpl支持MimeMessages和SimpleMailMessages。
     * MimeMessages为复杂邮件模板,支持文本、附件、html、图片等。
     * SimpleMailMessages实现了MimeMessageHelper,为普通邮件模板,支持文本
     */
    private SimpleMailMessage simpleMailMessage;
    /**
     * 描述:Spring 依赖注入
     */
    public void setMailSender(JavaMailSenderImpl mailSender) {
        this.mailSender = mailSender;
    }

    /**
     * 描述:Spring 依赖注入
     */
    public void setSimpleMailMessage(SimpleMailMessage simpleMailMessage) {
        this.simpleMailMessage = simpleMailMessage;
    }

    /**
     * 单发
     *
     * @param recipient 收件人
     * @param subject 主题
     * @param content 内容
     */
    public void send(String recipient,String subject,String content){
        System.out.println(simpleMailMessage);
        simpleMailMessage.setTo(recipient);
        simpleMailMessage.setSubject(subject);
        simpleMailMessage.setText(content);
        mailSender.send(simpleMailMessage);
    }

    /**
     * 群发
     *
     * @param recipients 收件人
     * @param subject 主题
     * @param content 内容
     */
    public void send(List<String> recipients,String subject,String content){
        simpleMailMessage.setTo(recipients.toArray(new String[recipients.size()]));
        simpleMailMessage.setSubject(subject);
        simpleMailMessage.setText(content);
        mailSender.send(simpleMailMessage);
    }

    /**
     * 发送带附件的邮件
     * @author malizhi
     * @param recipient
     * @param subject
     * @param content
     * @param file void
     * @version 1.0
     * @exception
     */
    public void sendWithFile(String recipient,String subject,String content,MultipartFile file){
        //使用JavaMail的MimeMessage,支付更加复杂的邮件格式和内容
        MimeMessage msg = mailSender.createMimeMessage();
        try {
            //创建MimeMessageHelper对象,处理MimeMessage的辅助类
            MimeMessageHelper helper = new MimeMessageHelper(msg, true);
            //使用辅助类MimeMessage设定参数
            helper.setFrom(mailSender.getUsername());
            helper.setTo(recipient);
            helper.setSubject(subject);
            helper.setText(content);
            //加入附件
            helper.addAttachment(file.getOriginalFilename(), file);
        } catch (MessagingException e) {
            e.printStackTrace();
        }
        // 发送邮件
        mailSender.send(msg);
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值