SSM项目环境快速搭建
SSM项目的环境搭建
环境搭建的目标
工程创建
创建父工程
创建空
maven
工程xxx-parent
作为父工程修改父工程中的
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>org.example</groupid>
<artifactid>FastSSMProjectBuild</artifactid>
<version>1.0-SNAPSHOT</version> <properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<spring.version>4.3.20.RELEASE</spring.version>
<mybatis.version>3.2.8</mybatis.version>
<mysql.version>5.1.3</mysql.version>
<druid.version>1.0.31</druid.version>
<spring-mybatis.version>1.2.2</spring-mybatis.version>
<pagehelper.version>4.0.0</pagehelper.version>
<aspectjweaver.version>1.9.2</aspectjweaver.version>
<cglib.version>2.2</cglib.version>
<slf4j-api.version>1.7.7</slf4j-api.version>
<logback-classic.version>1.2.3</logback-classic.version>
<jcl-over-slf4j.version>>1.7.25</jcl-over-slf4j.version>
<jul-to-slf4j.version>>1.7.25</jul-to-slf4j.version>
<jackson.version>2.9.8</jackson.version>
<jstl.version>1.2</jstl.version>
<junit.version>4.12</junit.version>
<servlet.version>2.5</servlet.version>
<jsp.version>2.1.3-b06</jsp.version>
<gson.version>2.8.5</gson.version>
<springsecurity.version>4.2.10.RELEASE</springsecurity.version>
</properties> <modules>
<module>WebProject</module>
<module>ServiceComp</module>
<module>DaoComp</module>
<module>ControllerComp</module>
<module>EntityComp</module>
<module>CommonComp</module>
</modules> <packaging>pom</packaging> <dependencymanagement>
<dependencies>
<!-- Spring 依赖 -->
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-orm</artifactid>
<version>${spring.version}</version>
</dependency> <dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-webmvc</artifactid>
<version>${spring.version}</version>
</dependency> <dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-test</artifactid>
<version>${spring.version}</version>
</dependency> <dependency>
<groupid>org.aspectj</groupid>
<artifactid>aspectjweaver</artifactid>
<version>${aspectjweaver.version}</version>
</dependency> <dependency>
<groupid>cglib</groupid>
<artifactid>cglib</artifactid>
<version>${cglib.version}</version>
</dependency> <!-- 数据库依赖 -->
<!-- MySQL 驱动 -->
<dependency>
<groupid>mysql</groupid>
<artifactid>mysql-connector-java</artifactid>
<version>${mysql.version}</version>
</dependency> <!-- 数据源 -->
<dependency>
<groupid>com.alibaba</groupid>
<artifactid>druid</artifactid>
<version>${druid.version}</version>
</dependency> <!-- MyBatis -->
<dependency>
<groupid>org.mybatis</groupid>
<artifactid>mybatis</artifactid>
<version>${mybatis.version}</version>
</dependency> <!-- MyBatis 与 Spring 整合 -->
<dependency>
<groupid>org.mybatis</groupid>
<artifactid>mybatis-spring</artifactid>
<version>${spring-mybatis.version}</version>
</dependency> <!-- MyBatis 分页插件 -->
<dependency>
<groupid>com.github.pagehelper</groupid>
<artifactid>pagehelper</artifactid>
<version>${pagehelper.version}</version>
</dependency> <!-- 日志 -->
<dependency>
<groupid>org.slf4j</groupid>
<artifactid>slf4j-api</artifactid>
<version>${slf4j-api.version}</version>
</dependency>
<dependency>
<groupid>ch.qos.logback</groupid>
<artifactid>logback-classic</artifactid>
<version>${logback-classic.version}</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>
<!-- Spring 进行 JSON 数据转换依赖 -->
<dependency>
<groupid>com.fasterxml.jackson.core</groupid>
<artifactid>jackson-core</artifactid>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupid>com.fasterxml.jackson.core</groupid>
<artifactid>jackson-databind</artifactid>
<version>${jackson.version}</version>
</dependency>
<!-- JSTL 标签库 -->
<dependency>
<groupid>jstl</groupid>
<artifactid>jstl</artifactid>
<version>${jstl.version}</version>
</dependency> <!-- junit 测试 -->
<dependency>
<groupid>junit</groupid>
<artifactid>junit</artifactid>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- 引入 Servlet 容器中相关依赖 -->
<dependency>
<groupid>javax.servlet</groupid>
<artifactid>servlet-api</artifactid>
<version>${servlet.version}</version>
<scope>provided</scope>
</dependency>
<!-- JSP 页面使用的依赖 -->
<dependency>
<groupid>javax.servlet.jsp</groupid>
<artifactid>jsp-api</artifactid>
<version>${jsp.version}</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupid>com.google.code.gson</groupid>
<artifactid>gson</artifactid>
<version>${gson.version}</version>
</dependency> <!-- SpringSecurity 对 Web 应用进行权限管理 -->
<dependency>
<groupid>org.springframework.security</groupid>
<artifactid>spring-security-web</artifactid>
<version>${springsecurity.version}</version>
</dependency>
<!-- SpringSecurity 配置 -->
<dependency>
<groupid>org.springframework.security</groupid>
<artifactid>spring-security-config</artifactid>
<version>${springsecurity.version}</version>
</dependency>
<!-- SpringSecurity 标签库 -->
<dependency>
<groupid>org.springframework.security</groupid>
<artifactid>spring-security-taglibs</artifactid>
<version>${springsecurity.version}</version>
</dependency>
</dependencies>
</dependencymanagement> <build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.yml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.yml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
注意:父工程的打包方式为
<packaging>pom</packaging>
在父工程中,使用
<dependencymanagement>
标签包裹<dependencies>
,故父类工程实际上只是声明了这些jar
包的引用,实际并没有包涵进来
创建子工程
注意事项:
在带
/WEB-INF/web.xml
的网络工程项目中,设置pom.xml
中的<packaging>war</packaging>
各个子项目在引入时,可以直接使用父项目中已经声明了的资源,如果不填写引入的
jar
包的版本号<version>
,那么默认引入的就是夫项目中指定的版本,也可以自己指定单独的版本如果不需要某个
jar
包中的某些牵连的依赖,可以使用<exclusion>
标签排除如果不同
module
之间需要项目引用,就需要在当前的pom.xml
的<dependencies>
标签中声明<dependencies>
<dependency>
<groupid>org.example</groupid>
<artifactid>EntityComp</artifactid>
<version>1.0-SNAPSHOT</version>
</dependency> <dependency>
<groupid>org.slf4j</groupid>
<artifactid>slf4j-api</artifactid>
</dependency> <dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-webmvc</artifactid>
<exclusions>
<exclusion>
<groupid>org.springframework</groupid>
<artifactid>spring-beans</artifactid>
</exclusion>
</exclusions>
</dependency>
</dependencies>
因为每个新的
module
都是通过 空的maven
项目创建的,所以在Web
项目中需要添加Web Framework
Spring整合 MyBatis
在子工程中加入搭建环境需要的依赖:
mysql-connector-java, mybatis, mybatis-spring, spring-tx, spring-orm,aspectjweaver, cglib, druid, pagehelper
创建
jdbc.properties
准备数据库连接相关的信息jdbc.user=root
jdbc.password=zhao
jdbc.url=jdbc:mysql://localhost:3306/project_crowd?useSSL=false&characterEncoding=UTF-8&useUnicode=true&serverTimezone=UTC
jdbc.driver=com.mysql.jdbc.Driver
创建
mybatis
的配置文件mybatis-config.xml
,具体的配置都可以放到spring
的配置文件中进行<!--?xml version="1.0" encoding="UTF-8"?--> <configuration> </configuration>
创建
spring
同数据库相关的配置文件spring-mybatis.xml
<!--?xml version="1.0" encoding="UTF-8"?-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemalocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 加载外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"> <!-- 配置数据源-->
<bean id="druid" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="username" value="${jdbc.user}">
<property name="password" value="${jdbc.password}">
<property name="url" value="${jdbc.url}">
<property name="driverClassName" value="${jdbc.driver}">
</property></property></property></property></bean> <!-- 配置 SqlSessionFactoryBean整合 MyBatis-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
<!-- 指定 MyBatis全局配置文件的位置-->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml">
<!-- 装配数据源-->
<property name="dataSource" ref="druid">
<!-- 指定 Mapper.xml配置文件的位置-->
<property name="mapperLocations" value="classpath:mybatis/mapper/*Mapper.xml"> <property name="plugins">
<array>
<!--配置 pageHelper插件-->
<bean class="com.github.pagehelper.PageHelper">
<!--配置相关属性-->
<property name="properties">
<props>
<!-- 配置数据库方言,告诉 PageHelper当前使用的数据库-->
<prop key="dialect">mysql</prop>
<!--配置页码的合理化修正:在 1~总页数之间修正页码-->
<prop key="reasonable">true</prop>
</props>
</property>
</bean>
</array>
</property>
</property></property></property></bean> <!-- 配置 MapperScannerConfigurer来扫描 Mapper接口所在的包-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" id="mapperScannerConfigurer">
<property name="basePackage" value="com.zwb.crowd.mapper">
</property></bean>
</context:property-placeholder></beans>
Spring的测试类
使用 JUnit4
对已有的代码进行测试时,因为需要使用 Spring
对类进行管理,所以相比以前使用 JUnit
时只添加 @Test
注解时,需要做更多的处理。
- 需要添加
@ContextConfiguration()
注解,设置locations
属性为需要加载的配置文件名称 - 添加
@RunWith()
注解,设置value
属性为SpringJUnit4ClassRunner.class
比如:
import com.zwb.crowd.entity.Admin;
import com.zwb.crowd.entity.Menu;
import com.zwb.crowd.entity.Role;
import com.zwb.crowd.exception.LoginAcctDuplicateException;
import com.zwb.crowd.mapper.AdminMapper;
import com.zwb.crowd.mapper.RoleMapper;
import com.zwb.crowd.service.api.AdminService;
import com.zwb.crowd.service.api.MenuService;
import com.zwb.crowd.util.CrowdUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
/**
* @author :OliQ
* @date :Created in 2021/8/8 14:13
* <p>
* 在类上标记必要的注解,Spring整合 JUnit
*/
@ContextConfiguration(locations = {"classpath:spring-persist-mybatis.xml", "classpath:spring-persist-tx.xml", "classpath:spring-web-mvc.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class CrowdTest {
@Autowired
private DataSource dataSource;
@Autowired
private MenuService menuService;
@Autowired
private AdminMapper adminMapper;
@Autowired
private AdminService adminService;
@Autowired
private RoleMapper roleMapper;
@Autowired
private PasswordEncoder passwordEncoder;
@Test
public void testBCrypt() {
System.out.println("oliver: " + passwordEncoder.encode("oliver"));
System.out.println("adminOperator: " + passwordEncoder.encode("adminOperator"));
System.out.println("roleOperator: " + passwordEncoder.encode("roleOperator"));
}
@Test
public void testGetAllMenu() {
List</p><menu> all = menuService.getAll();
System.out.println(all);
}
@Test
public void createSomeTestRoles() {
for (int i = 0; i < 123; i++) {
Role role = new Role(null, "test" + i);
roleMapper.insert(role);
}
}
@Test
public void createSomeTestAdmins() throws LoginAcctDuplicateException {
for (int i = 0; i < 132; i++) {
Admin admin = new Admin(null, "test" + i, null, "test" + i, "test" + i + "@qq.com", null);
admin.setUserPswd(CrowdUtil.md5("test" + i));
adminService.saveAdmin(admin);
}
}
@Test
public void testTx() throws LoginAcctDuplicateException {
Admin admin = new Admin(null, "tom", "tom", "杰瑞", "jerry@qq.com", null);
adminService.saveAdmin(admin);
}
@Test
public void testLog() {
// 获取 Logger对象,传入的一般就是当前类
Logger logger = LoggerFactory.getLogger(CrowdTest.class);
// 根据不同的日志级别打印日志
logger.debug("Hello I am in Debug level");
logger.debug("Hello I am in Debug level");
logger.debug("Hello I am in Debug level");
logger.info("Info level");
logger.info("Info level");
logger.info("Info level");
logger.warn("warning warning warning");
logger.warn("warning warning warning");
logger.warn("warning warning warning");
logger.error("error");
logger.error("error");
logger.error("error");
}
@Test
public void testInsertAdmin() {
Admin admin = new Admin(null, "oliver", "oliver", "oliver", "oli@qq.com", null);
int insert = adminMapper.insert(admin);
// sysout的打印方式本质上是一个 IO操作,比较消耗性能不能在上线后使用
// 即使上线前删除,也很可能有遗漏,而且非常的麻烦
// 如果选用日志系统,就可以通过日志的级别控制信息的打印
System.out.println(insert);
}
@Test
public void testSelectAdmin() {
Admin admin = adminMapper.selectByPrimaryKey(1);
System.out.println(admin);
}
@Test
public void testConnection() throws SQLException {
Connection connection = dataSource.getConnection();
System.out.println(connection);
}
}
日志系统
在系统运行过程中,往往会出现这样那样的错误,我们需要通过日志进行排查
为什么使用日志而不是 sysout?
- sysout 如果不删除,那么执行到这里必然会打印;
- 如果使用日志方式打印,可以通过日志级别控制信息是否打印
- sysout性能影响大些
框架日志系统的替换
默认情况下,slf4j
会搭配 commons-logging
进行使用,此时像 Spring
和 MyBatis
并不会通过 slf4j
进行日志打印。所以我们需要进行框架日志系统的替换。
<!-- 替换掉 commons-logging -->
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-orm</artifactid>
<exclusions>
<exclusion>
<groupid>commons-logging</groupid>
<artifactid>commons-logging</artifactid>
</exclusion>
</exclusions>
</dependency>
<!-- 加入转换包 -->
<dependency>
<groupid>org.slf4j</groupid>
<artifactid>jcl-over-slf4j</artifactid>
<version>1.7.25</version>
</dependency>
添加 logback配置文件
为了规范化日志的打印格式,可以在 resources
目录下添加配置文件 logback.xml
<!--?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="DEBUG">
<!-- 指定打印日志的 appender,这里通过“STDOUT”引用了前面配置的 appender -->
<appender-ref ref="STDOUT">
</appender-ref></root>
<!-- 根据特殊需求指定局部日志级别 -->
<logger name="com.zwb.crowd.mapper" level="DEBUG">
</logger></configuration>
声明式事物
使用 Spring
来全面接管数据库事务,使用 声明式代替 编程式
try {
// 核心操作前:开启事务(关闭自动提交)
// 对应 AOP 的前置通知
connection.setAutoCommit(false);
// 核心操作
adminService.updateXxx(xxx, xxx);
// 核心操作成功:提交事务
// 对应 AOP 的返回通知
connection.commit();
} catch (Exception e) {
// 核心操作失败:回滚事务
// 对应 AOP 的异常通知
connection.rollBack();
} finally {
// 不论成功还是失败,核心操作终归是结束了
// 核心操作不管是怎么结束的,都需要释放数据库连接
// 对应 AOP 的后置通知
if (connection != null) {
connection.close();
}
}
需要加入的依赖是:
- aspectjweaver
- cglib
<!-- AOP 所需依赖 -->
<dependency>
<groupid>org.aspectj</groupid>
<artifactid>aspectjweaver</artifactid>
</dependency>
<!-- AOP 所需依赖 -->
<dependency>
<groupid>cglib</groupid>
<artifactid>cglib</artifactid>
</dependency>
XML配置事物
创建 xml配置文件 spring-tx.xml
<!--?xml version="1.0" encoding="UTF-8"?-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 配置自动扫描的包,主要是为了把 Service扫描到 IOC容器中-->
<context:component-scan base-package="com.zwb.crowd.service">
<!-- 配置事物管理器-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="dataSourceTransactionManager">
<!-- 装配数据源-->
<property name="dataSource" ref="druid">
</property></bean>
<!-- 配置事务的切面-->
<aop:config>
<!-- 考虑到 SpringSecurity中,避免把 UserDetailsService加入到事物控制中,让切入点表达式定位到 ServiceImpl-->
<aop:pointcut id="txPointcut" expression="execution(* *..*ServiceImpl.*(..))">
<!-- 将切入点表达式和事物通知关联起来-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut">
</aop:advisor></aop:pointcut></aop:config>
<!-- 配置事物的通知-->
<tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
<!-- 配置事物的属性-->
<tx:attributes>
<!-- 查询的方法:配置只读属性,进行优化-->
<!--
在基于 XML的声明式事物中,tx:method是必须配置的,
如果某个方法没有配置对应的 tx:method,那么事务对这个方法就不生效
-->
<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">
<!-- 增删改方法:配置事物的传播行为,回滚异常-->
<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:method></tx:method></tx:method></tx:method></tx:method></tx:method></tx:method></tx:method></tx:attributes>
</tx:advice>
</context:component-scan></beans>
Spring整合 SpringMVC
加入依赖
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-webmvc</artifactid>
</dependency>
配置 web.xml
<!--?xml version="1.0" encoding="UTF-8"?-->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
<!-- 配置 ContextLoaderListener加载 Spring配置文件-->
<!--<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-persist-*.xml</param-value>
</context-param>-->
<!--<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>-->
<!-- 配置 DispatcherServlet-->
<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执行的顺序要在所有其他Filter前面 -->
<!-- 原因如下: -->
<!-- request.setCharacterEncoding(encoding)必须在request.getParameter()前面 -->
<!-- response.setCharacterEncoding(encoding)必须在response.getWriter()前面 -->
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-*.xml</param-value>
</init-param>
<!-- Servlet默认生命周期中,创建对象是在第一次接收到请求时 -->
<!-- 而DispatcherServlet创建对象后有大量的“框架初始化”工作,不适合在第一次请求时来做 -->
<!-- 设置load-on-startup就是为了让DispatcherServlet在Web应用启动时创建对象、初始化 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map all requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<!-- url-pattern配置方式一:/表示拦截所有请求 -->
<!-- <url-pattern>/</url-pattern> -->
<!-- url-pattern配置方式二:配置请求扩展名 -->
<!-- 优点1:xxx.css、xxx.js、xxx.png等等静态资源完全不经过SpringMVC,不需要特殊处理 -->
<!-- 优点2:可以实现伪静态效果。表面上看起来是访问一个HTML文件这样的静态资源,但是实际上是经过Java代码运算的结果。 -->
<!-- 伪静态作用1:给黑客入侵增加难度。 -->
<!-- 伪静态作用2:有利于SEO优化(让百度、谷歌这样的搜索引擎更容易找到我们项目)。 -->
<!-- 缺点:不符合RESTFul风格 -->
<url-pattern>*.html</url-pattern>
<!-- 为什么要另外再配置json扩展名呢? -->
<!-- 如果一个Ajax请求扩展名是html,但是实际服务器给浏览器返回的是json数据,二者就不匹配了,会出现406错误。 -->
<!-- 为了让Ajax请求能够顺利拿到JSON格式的响应数据,我们另外配置json扩展名 -->
<url-pattern>*.json</url-pattern>
</servlet-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
注意:CharacterEncodingFilter
是为了解决 POST 请求的字符乱码问题,在 web.xml 中存在多个 Filter
时,让这个 Filter 作为过滤器链中的第一个 Filter
创建 SpringMVC
的配置文件 spring-webmvc.xml
<!--?xml version="1.0" encoding="UTF-8"?-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<import resource="classpath:spring-persist-tx.xml">
<import resource="classpath:spring-persist-mybatis.xml">
<!-- 配置注解驱动-->
<mvc:annotation-driven>
<!-- 配置自动扫描的包路径-->
<context:component-scan base-package="com.zwb.crowd.mvc">
<mvc:default-servlet-handler>
<!-- 配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="resolver">
<property name="prefix" value="/WEB-INF/">
<property name="suffix" value=".jsp">
</property></property></bean>
<!-- 配置基于 XML的异常映射-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" id="exceptionResolver">
<!-- 配置异常类型和具体视图的对应关系时-->
<property name="exceptionMappings">
<props>
<!-- key属性指定异常全类名,标签体中指定对应的视图名(不需要写前后缀,它也会通过视图解析器的)-->
<prop key="java.lang.Exception">system-error</prop>
</props>
</property>
</bean>
<!-- 配置 view-controller,直接把请求地址和视图名称关联起来,不必再写 Controller方法了-->
<mvc:view-controller path="/admin/to/login/page.html" view-name="admin-login">
<mvc:view-controller path="/admin/to/main/page.html" view-name="admin-main">
<mvc:view-controller path="/admin/to/add/page.html" view-name="admin-add">
<mvc:view-controller path="/role/to/page.html" view-name="role-page">
<mvc:view-controller path="/menu/to/page.html" view-name="menu-page">
<!-- 注册拦截器-->
<!--<mvc:interceptors>
<mvc:interceptor>
<!– mapping 是配置要拦截的资源–>
<!– /*表示一层路径,如:/a–>
<!– /**表示多层路径,如:/aaa/bbb/cc–>
<mvc:mapping path="/**"/>
<!– exclude-mapping 是配置不拦截的资源–>
<mvc:exclude-mapping path="/admin/to/login/page.html"/>
<mvc:exclude-mapping path="/admin/do/login.html"/>
<mvc:exclude-mapping path="/admin/to/login/quit.html"/>
<!– 具体的拦截器的类–>
<bean class="com.zwb.crowd.mvc.interceptor.LoginInterceptor" id="loginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>-->
</mvc:view-controller></mvc:view-controller></mvc:view-controller></mvc:view-controller></mvc:view-controller></mvc:default-servlet-handler></context:component-scan></mvc:annotation-driven></import></import></beans>
前端 JSP页面
加入依赖
<!-- 引入 Servlet 容器中相关依赖 -->
<dependency>
<groupid>javax.servlet</groupid>
<artifactid>servlet-api</artifactid>
<scope>provided</scope>
</dependency>
<!-- JSP 页面使用的依赖 -->
<dependency>
<groupid>javax.servlet.jsp</groupid>
<artifactid>jsp-api</artifactid>
<scope>provided</scope>
</dependency>
在页面上添加 <base>
标签,保证其中的页面跳转、超链接等都基于一个共同的网站名
<base href="http://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/">
需要注意的点:
<base>
标签必须写在 ``标签内<base>
标签必须写在带有具体路径的标签前面serverName
部分 EL 表达式和serverPort
部分 EL 表达式之间必须写“:”erverPort
部分 EL表达式和contextPath
部分EL表达式之间绝对不能写“/”- 原因:
contextPath
部分 EL 表达式本身就是“/”开头 - 如果多写一个“/”会干扰 Cookie 的工作机制
- 原因:
serverPort
部分 EL 表达式后面必须写“/”
异常映射
作用:统一管理项目中的异常
- 抛出异常
- 显示异常信息
- 普通请求:在页面上显示异常信息
- Ajax 请求:返回 JSON 数据
因为针对不同的请求,我们都需要返回不同的数据,所以需要鉴定请求的类型。
判断依据:判断请求头中 Accept: application/json, text/javascript; X-Request-With: XMLHttpRequest
/**
* 判断是否是 Ajax请求
*
* @return
*/
public static boolean judgeRequestType(HttpServletRequest request) {
// 获取请求消息头
String acceptHeader = request.getHeader("Accept");
String xRequestHeader = request.getHeader("X-Requested-With");
return (acceptHeader != null && acceptHeader.contains("application/json"))
|| (xRequestHeader != null && xRequestHeader.equals("XMLHttpRequest"));
}
基于 XML的异常映射方式
在 spring-web-mvc.xml
中做如下配置
<!-- 配置基于 XML的异常映射-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" id="exceptionResolver">
<!-- 配置异常类型和具体视图的对应关系时-->
<property name="exceptionMappings">
<props>
<!-- key属性指定异常全类名,标签体中指定对应的视图名(不需要写前后缀,它也会通过视图解析器的)-->
<prop key="java.lang.Exception">system-error</prop>
</props>
</property>
</bean>
基于注解的异常映射方式
加入 JSON处理相关的依赖
<dependency>
<groupid>com.google.code.gson</groupid>
<artifactid>gson</artifactid>
<version>2.8.5</version>
</dependency>
package com.zwb.crowd.mvc.config;
/**
* @author :OliQ
* @date :Created in 2021/8/10 17:29
* <p>
* @ControllerAdvice 表示当前类是一个基于注解的异常处理器类
* @EXceptionHandler 将一个具体的异常类型和一个方法关联起来
*/
@ControllerAdvice
public class CrowdExceptionResolver {
@ExceptionHandler(value = LoginAcctDuplicatForUpdateException.class)
public ModelAndView resolveLoginAcctDuplicatForUpdateException(LoginAcctDuplicatForUpdateException exception, HttpServletRequest request, HttpServletResponse response) throws IOException {
// 设置需要跳转的页面名称
String viewName = "system-error";
return commonResolve(viewName, exception, request, response);
}
@ExceptionHandler(value = LoginAcctDuplicateException.class)
public ModelAndView resolveLoginAcctDuplicateException(LoginAcctDuplicateException exception, HttpServletRequest request, HttpServletResponse response) throws IOException {
String viewName = "admin-add";
return commonResolve(viewName, exception, request, response);
}
@ExceptionHandler(value = LoginFailedException.class)
public ModelAndView resolveLoginFailedException(LoginFailedException exception, HttpServletRequest request, HttpServletResponse response) throws IOException {
String viewName = "admin-login";
return commonResolve(viewName, exception, request, response);
}
/**
* 处理 空指针异常
*
* @param exception
* @param request
* @param response
* @return
* @throws IOException
*/
@ExceptionHandler(value = NullPointerException.class)
public ModelAndView resolveNullPointerException(
// 实际捕获到的异常类型
NullPointerException exception,
// 当前请求对象
HttpServletRequest request,
HttpServletResponse response) throws IOException {
String viewName = "system-error";
// 返回 ModelAndView
return commonResolve(viewName, exception, request, response);
}
/**
* 处理数学异常(测试用)
*
* @param exception
* @param request
* @param response
* @return
* @throws IOException
*/
@ExceptionHandler(value = ArithmeticException.class)
public ModelAndView resolveArithmeticException(ArithmeticException exception, HttpServletRequest request, HttpServletResponse response) throws IOException {
String viewName = "system-error";
return commonResolve(viewName, exception, request, response);
}
/**
* 实际的异常处理的方法
*
* @param viewName
* @param exception
* @param request
* @param response
* @return
* @throws IOException
*/
private ModelAndView commonResolve(String viewName,
Exception exception,
HttpServletRequest request,
HttpServletResponse response) throws IOException {
// 判断当前请求类型
boolean result = CrowdUtil.judgeRequestType(request);
// 如果是 Ajax请求
if (result) {
// 创建一个 ResultEntity对象
ResultEntity<object> failed = ResultEntity.failed(exception.getMessage());
// 创建 Gson对象
Gson gson = new Gson();
// 将 ResultEntity对象转换为 JSON字符串
String json = gson.toJson(failed);
// 将 JSON字符串作为响应体返回给浏览器
response.getWriter().write(json);
// 由于上面已经通过了 Response对象返回了响应,所以不提供了 ModelAndView
return null;
}
// 如果 不是 Ajax请求
ModelAndView mv = new ModelAndView();
// 将 Exception对象存入模型
mv.addObject(CrowdConstant.ATTR_NAME_EXCEPTION, exception);
// 设置对应的视图
mv.setViewName(viewName);
return mv;
}
}
常量处理
在请求返回中经常需要返回某些特定的常量值,因此可以将其设置为 静态的常量值
package com.zwb.crowd.constant;
/**
* @author :OliQ
* @date :Created in 2021/8/11 14:09
*/
public class CrowdConstant {
// 异常处理后返回的属性名
public static final String ATTR_NAME_EXCEPTION = "exception";
// 已登录的管理员
public static final String ATTR_NAME_LOGIN_ADMIN = "loginAdmin";
public static final String ATTR_NAME_PAGE_INFO = "pageInfo";
// 账号名重复
public static final String MESSAGE_LOGIN_REPETITIONAL = "系统错误,账号名不唯一";
// 登陆失败
public static final String MESSAGE_LOGIN_FAILED = "登陆失败,账号或密码错误!";
// 注册失败,账号已存在
public static final String MESSAGE_LOGIN_ACCOUNT_DUPLICATE = "该账号已被注册!";
// 注册或者登陆输入的密码不合法
public static final String MESSAGE_LOGIN_PASSWORD_INVALIDATE = "密码不合法 !";
// 未登录就访问资源
public static final String MESSAGE_ACCESS_FORBIDEN = "尚未登陆,访问受限!";
}
异步值的返回
当处理 Ajax请求,需要返回数据时,不能简单的返回数据库查到的值。
需要使用一个特定的类,内含 请求操作的结果标识和数据
package com.zwb.crowd.util;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 统一整个项目中 Ajax请求返回的结果
*
* @author :OliQ
* @date :Created in 2021/8/10 16:36
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
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;
/**
* 请求处理成功且不需要返回数据时
*
* @param <e>
* @return
*/
public static <e> ResultEntity<e> successWithoutData() {
return new ResultEntity<e>(SUCCESS, null, null);
}
/**
* 请求处理成功且需要返回数据时
*
* @param e
* @param <e>
* @return
*/
public static <e> ResultEntity<e> successWithData(E e) {
return new ResultEntity<e>(SUCCESS, null, e);
}
/**
* 请求处理失败
*
* @param message
* @param <e>
* @return
*/
public static <e> ResultEntity<e> failed(String message) {
return new ResultEntity<>(FAILED, message, null);
}
}
SSM项目环境快速搭建的更多相关文章
- Java Web 开发环境快速搭建
Java Web 开发环境快速搭建 在因某种原因更换开发设备后,可依据此文快速搭建开发环境,恢复工作环境. Java开发环境: Windows 10 (64-bit) Oralce JDK Eclip ...
- ASP.NET MVC项目框架快速搭建实战
MVC项目搭建笔记---- 项目框架采用ASP.NET MVC+Entity Framwork+Spring.Net等技术搭建,采用”Domain Model as View Model“的MVC开发 ...
- JAVA学习:maven开发环境快速搭建
转自:http://tech.it168.com/a2011/1204/1283/000001283307.shtml 最近,开发中要用到maven,所以对maven进行了简单的学习.因为有个mave ...
- golang开源项目qor快速搭建网站qor-example运行实践
最近想找几个基于Go语言开发的简单的开源项目学习下,分享给大家,github上有心人的收集的awesome-go项目集锦:github地址 发现一个Qor项目: Qor 是基于 Golang 开发的的 ...
- maven环境快速搭建(转)
出处:http://www.cnblogs.com/fnng/archive/2011/12/02/2272610.html 最近,开发中要用到maven,所以对maven进行了简单的学习.因为有个m ...
- windows Android开发环境快速搭建和部署
windows安装Android的开发环境相对来说比较简单,本文写给第一次想在自己Windows上建立Android开发环境的朋友们,为了确保大家能顺利完成开发环境的搭建,文章写的尽量详细,希望对初级 ...
- Java 以及JEE环境快速搭建
吐槽一下 博主最近找了一个Java Development的实习,加上上个月末的考试周,所以很久没有更新博客. 上了一周的班,还没有在熟悉项目的阶段. 感想:哇,读别人的代码是一件很费力的事情啊!!! ...
- lnmp环境快速搭建及原理解析
刚开始学习php的时候是在wamp环境下开发的,后来才接触到 lnmp 环境当时安装lnmp是按照一大长篇文档一步步的编译安装,当时是真不知道是在做什么啊!脑袋一片空白~~,只知道按照那么长的一篇文档 ...
- vue项目环境的搭建
首先要明白Vue是基于node的,在公司要使用vue来开发项目的话肯定是要先安装node的,下面是搭建一个最简单的vue项目环境 一 安装node 这个可以去node的官网下载对应版本 安装好之后 c ...
随机推荐
- mysql 跨库事务XA
前一段时间在工作中遇到了跨库事务问题,后来在网上查询了一下,现在做一下整理和总结. 1.首先要确保mysql开启XA事务支持 SHOW VARIABLES LIKE '%XA%' 如果innodb_s ...
- Javascript 正则使用笔记
# 一.如何创建正则表达式对象 # 1.通过RegExp构造函数来创建.i代表忽略大小写,g代表全局搜索(非全局搜索正则只匹配第一次符合的内容,全局搜索可以匹配多次). var reg = new R ...
- mui 登录跳转到首页之后顶部选项卡不灵敏问题
前段时间开发一个用mui开发app的时候遇到了登录跳转到首页之后顶部选项卡会失灵的问题,多次尝试之后终于解决了,趁现在还有点印象记录一下吧. 一开始我是用mui.openWindow来新开首页的,出了 ...
- Apache Pulsar Summit Asia 2020 正式启动,演讲议题征集中!
Apache Pulsar Summit 是 Apache Pulsar 社区年度盛会,它将分布在世界各地的 Apache Pulsar 项目 Contributor.Commiter 和各企业 CT ...
- Spring 03 切面编程
简介 AOP(Aspect Oriented Programming),即面向切面编程 这是对面向对象思想的一种补充. 面向切面编程,就是在程序运行时,不改变程序源码的情况下,动态的增强方法的功能. ...
- 052_末晨曦Vue技术_处理边界情况之程序化的事件侦听器
程序化的事件侦听器 点击打开视频讲解更详细 现在,你已经知道了 $emit 的用法,它可以被 v-on 侦听,但是 Vue 实例同时在其事件接口中提供了其它的方法.我们可以: 通过 $on(event ...
- HCIA-Datacom 3.1 实验一:以太网基础与VLAN配置实验
实验介绍: 以太网是一种基于CSMA/CD(Carrier Sense Multiple Access/Collision Detection)的共享通讯介质的数据网络通讯技术.当主机数目较多时会导致 ...
- for循环与range的使用
for循环与range的使用 for循环 for循环的本质 for循环和while循环功能基本一致,while循环可以做到的事情for循环也都可以做到,但是for循环可以给他增加一个定义循环次数和范围 ...
- 【java】学习路径40-Buffer缓冲区输入流
@Testpublic void testBufferInputStream(){ BufferedInputStream bfis = null; try { bfis = new Buffered ...
- v-if和v-for的优先级是什么?
一.作用 v-if 指令用于条件性地渲染一块内容.这块内容只会在指令的表达式返回 true值的时候被渲染 v-for 指令基于一个数组来渲染一个列表.v-for 指令需要使用 item in item ...