[toc]
spring
注解:
@RequestMapping
- produces:指定返回值类型,设定返回值的字符编码;
- consumes:指定处理请求的提交内容类型(Content-Type)
新建一个基于maven的web项目
具体步骤如下:
这里有两种方式创建一个maven project
- 第一种
一般创建出来的maven project的pom.xml文件都会报错,因为缺少web.xml,在webapp
下创建WEB-INF
新建一个web.xml即可解决该错误
- 第二种
创建完工程之后,就需要配置项目所依赖的各种jar包
pom.xml文件
<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>这里的内容是上面新建maven项目中的GroupId</groupId>
<artifactId>这里的内容是ArtifactId</artifactId>
<version>这里是选的Version</version>
<packaging>这里是选择的Packaging,web工程选择war</packaging>
<!--集中定义依赖版本号 -->
<properties>
<jdk.version>1.8</jdk.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>5.0.0.RELEASE</spring.version>
<spring.security.version>4.2.3.RELEASE</spring.security.version>
... ... ...
<mybatis.version>3.4.5</mybatis.version>
<mybatis-spring.version>1.3.1</mybatis-spring.version>
<mysql.version>6.0.6</mysql.version>
<druid.version>1.1.5</druid.version>
<thymeleaf.version>3.0.11.RELEASE</thymeleaf.version>
</properties>
<dependencies>
<!-- 文件上传 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
... ...
<!-- 前台框架 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>${thymeleaf.version}</version>
</dependency>
<!-- Version 3.0.4.RELEASE - for Thymeleaf 3.0 (requires Thymeleaf 3.0.10+) -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!--spring 核心 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
... ...
<!-- Spirng DAO -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring Web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
... ... ...
<!-- spring-security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${spring.security.version}</version>
</dependency>
... ... ...
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.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>
... ... ...
</dependencies>
<!-- maven编译用的版本控制,控制jdk的版本不会回跳 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
SSM框架整合
web.xml
<!--web.xml-->
<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" metadata-complete="true">
<!-- 如果是用mvn命令生成的xml,需要修改servlet版本为3.1 -->
<!-- 配置DispatcherServlet -->
<servlet>
<servlet-name>Springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置springMVC需要加载的配置文件 spring-dao.xml,spring-service.xml,spring-web.xml
Mybatis - > spring -> springmvc -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/spring-*.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Springmvc</servlet-name>
<!-- 默认匹配所有的请求/ -->
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!-- 解决乱码问题 -->
<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>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
在resources
下新建mybatis-config.xml
,jdbc.properties
,新建spring
文件夹,在该文件夹下分别新建spring-dao.xml,spring-service.xml,spring-web.xml
spring-dao.xml
<!--spring-dao.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置整合mybatis过程 -->
<!-- 1.配置数据库相关参数的文件 -->
<context:property-placeholder location="classpath:jdbc.properties" />
<!--2.数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<!-- 数据库基本信息配置 -->
<property name="url" value="${druid.url}" />
<property name="username" value="${druid.username}" />
<property name="password" value="${druid.password}" />
<property name="driverClassName" value="${druid.driverClassName}" />
<property name="filters" value="${druid.filters}" />
<!-- 最大并发连接数 -->
<property name="maxActive" value="${druid.maxActive}" />
<!-- 初始化连接数量 -->
<property name="initialSize" value="${druid.initialSize}" />
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="${druid.maxWait}" />
<!-- 最小空闲连接数 -->
<property name="minIdle" value="${druid.minIdle}" />
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="${druid.timeBetweenEvictionRunsMillis}" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="${druid.minEvictableIdleTimeMillis}" />
<property name="validationQuery" value="${druid.validationQuery}" />
<property name="testWhileIdle" value="${druid.testWhileIdle}" />
<property name="testOnBorrow" value="${druid.testOnBorrow}" />
<property name="testOnReturn" value="${druid.testOnReturn}" />
<property name="maxOpenPreparedStatements" value="${druid.maxOpenPreparedStatements}" />
<!-- 打开 removeAbandoned 功能 -->
<property name="removeAbandoned" value="${druid.removeAbandoned}" />
<!-- 1800 秒,也就是 30 分钟 -->
<property name="removeAbandonedTimeout" value="${druid.removeAbandonedTimeout}" />
<!-- 关闭 abanded 连接时输出错误日志 -->
<property name="logAbandoned" value="${druid.logAbandoned}" />
</bean>
<!-- 3.配置sqlSession -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource" />
<!-- 配置MyBaties全局配置文件:mybatis-config.xml -->
<property name="configLocation" value="classpath:mybatis-config.xml" />
<!-- 扫描entity包 使用别名 -->
<property name="typeAliasesPackage" value="cn.caams.coop.sale.entity" />
<!-- 扫描sql配置文件:mapper需要的xml文件 -->
<property name="mapperLocations" value="classpath:mapper/*.xml" />
</bean>
<!-- 4.配置扫描Dao接口包,动态实现Dao接口,注入到spring容器中 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入sqlSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
<!-- 给出需要扫描Dao接口包 -->
<property name="basePackage" value="cn.caams.coop.sale.dao" />
</bean>
</beans>
spring-service.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns: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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="cn.caams.coop.sale.security" />
<!-- 扫描service包下所有使用注解的类型 -->
<context:component-scan base-package="cn.caams.coop.sale.service" />
<!-- 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置基于注解的声明式事务 -->
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
spring-web.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:mvc="http://www.springframework.org/schema/mvc"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<!-- 配置SpringMVC -->
<!-- 1.开启SpringMVC注解模式 -->
<!-- 简化配置: (1)自动注册DefaultAnootationHandlerMapping,AnotationMethodHandlerAdapter
(2)提供一些列:数据绑定,数字和日期的format @NumberFormat, @DateTimeFormat, xml,json默认读写支持 -->
<mvc:annotation-driven />
<!-- 3.配置前端框架 -->
<bean id="templateResolver"
class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/" />
<property name="suffix" value=".html" />
<property name="characterEncoding" value="UTF-8" />
<property name="order" value="1" />
<property name="templateMode" value="HTML5" />
<property name="cacheable" value="false" />
</bean>
<bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver" />
</bean>
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine" />
<property name="characterEncoding" value="UTF-8" />
</bean>
<!-- 4.扫描web相关的bean -->
<context:component-scan base-package="cn.caams.coop.sale.controller" />
<!-- 定义文件上传解析器 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设定默认编码 -->
<property name="defaultEncoding" value="UTF-8"></property>
<!-- 设定文件上传的最大值5MB,5*1024*1024 -->
<property name="maxUploadSize" value="5242880"></property>
</bean>
</beans>
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 配置全局属性 -->
<settings>
<!-- 使用jdbc的getGeneratedKeys获取数据库自增主键值 -->
<setting name="useGeneratedKeys" value="true" />
<!-- 使用列别名替换列名 默认:true -->
<setting name="useColumnLabel" value="true" />
<!-- 开启驼峰命名转换:Table{create_time} -> Entity{createTime} -->
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
</configuration>
jdbc.properties
#阿里连接池配置
druid.driverClassName=com.mysql.jdbc.Driver
druid.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
druid.username=root
druid.password=123456
#初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
druid.initialSize=0
#最大连接池数量
druid.maxActive=20
#已经不再使用,配置了也没效果
druid.maxIdle=20
#定义最小空闲,最小连接池数量
druid.minIdle=1
#定义最长等待时间,获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁
druid.maxWait=60000
#属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有:
#监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wall
druid.filters=stat
#有两个含义:
#1) Destroy线程会检测连接的间隔时间2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明
druid.timeBetweenEvictionRunsMillis=60000
druid.minEvictableIdleTimeMillis=300000
#用来检测连接是否有效的sql,要求是一个查询语句。
#如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用
druid.validationQuery=SELECT 'x'
#建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,
#如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
druid.testWhileIdle=true
#申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
druid.testOnBorrow=false
#归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
druid.testOnReturn=false
#要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。
#在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100
druid.maxOpenPreparedStatements=100
druid.removeAbandoned=true
druid.removeAbandonedTimeout=1800
druid.logAbandoned=true
集成spring-security
首先在pom.xml
文件中添加依赖
<properties>
<spring.security.version>x.x.x.RELEASE</spring.security.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${spring.security.version}</version>
</dependency>
... ... ...
</dependencies>
使用Java Config的方式配置Spring security
1.需要新建一个类集成AbstractSecurityWebApplicationInitializer
,否则过滤器不起作用,相等于web.xml中配置过滤器
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {}
2.WebSecurityConfig extends WebSecurityConfigurerAdapter配置安全策略
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//自定义UserDetailsService用于配置用户信息服务:账号、密码、权限等
@Bean
@Override
protected UserDetailsService userDetailsService() {
return new UserDetailsServiceImpl();
}
//密码编码器:定义密码比对方式
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationProvider authenticationProvider(){
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService());
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
AuthenticationManager manager = super.authenticationManagerBean();
return manager;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
//配置静态资源
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**","/js/**","/image/**","/img/**");
}
//配置安全拦截机制——很重要
@Override
protected void configure(HttpSecurity http) throws Exception {
//关闭csrf,不在这里关闭的话,就需要在html等文件中添加token
http.csrf().disable()
//开启表单登录
.formLogin()
//自定义的登录页url,因为spring-security默认有一个登录页面
.loginPage("/home/login.do")
//登录请求拦截的url,这里的url必须要和提交登录表单的url一值,但我们不必书写这个url的逻辑
.loginProcessingUrl("/acction/login.do")
//登录成功后的处理
//.successHandler(AuthenticationSuccessHandler)
//认证成功之后,跳转的请求
.successForwardUrl("/home/index.do")
.and()
.authorizeRequests()
//.antMatchers("").hasAuthority("P"):只有P权限才能访问
//允许访问
.antMatchers("/page/login_page.html","/home/*").permitAll()
//其他的都需要进行认证,才能通过
.anyRequest().authenticated()
.and()
//配置session管理策略,可以设置会话控制参数
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
//退出登录相关的逻辑,spring security默认退出的url是/logout,默认返回的界面是配置的loginPage
.logout()
;
}
}
3.UserDetailsServiceImpl implements UserDetailsService
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserService userService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userService.queryUserByUserName(username);
if (user == null) {
throw new UsernameNotFoundException("用户名/密码无效");
}
//.authorities(AuthorityUtils.commaSeparatedStringToAuthorityList("admin"))注意这里,必须要有值,不能为null,否则会报错
UserDetails userDetails =
org.springframework.security.core.userdetails.User.withUsername(user.getUsername()).password(user.getPassword()).authorities(AuthorityUtils.commaSeparatedStringToAuthorityList("admin")).build();
return userDetails;
}
}
4.在使用Thymeleaf前端为前端框架的html中使用sec:*获得一些用户登录之后的信息
<!--pom.xml添加-->
<!-- Version 3.0.4.RELEASE - for Thymeleaf 3.0 (requires Thymeleaf 3.0.10+) -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
<!-- spring-web.xml中配置SpringSecurityDialect-->
<bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine">
<!-- 为了在thymeleaf中使用使用sec:* -->
<property name="additionalDialects">
<set>
<!--修改为自己的springsecurity版本-->
<bean
class="org.thymeleaf.extras.springsecurity4.dialect.SpringSecurityDialect" />
</set>
</property>
</bean>
<!--html中使用-->
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
...
<span class="login_or_register_string">
<!--判断是否有登陆,用户未登录显示登录两个字,登录之后显示用户名-->
<a th:href="@{/home/login.do}" sec:authorize="isAnonymous()" id="user_name_a" >登录</a>
<a class="user_name_a" sec:authorize="isAuthenticated()" sec:authentication="name" id="user_name_a"></a>
</span>
...
</html>
注解
//@Secured注解可以使用
@EnableGlobalMethodSecurity(securedEnabled=true)
//拥有normal或者admin角色的用户可以访问,Secured注解无法同时拥有admin&normal
@Secured({"ROLE_normal","ROLE_admin"})
//拦截@PreAuthrize,@PostAuthorize注解
@EnableGlobalMethodSecurity(prePostEnabled=true)
//拥有normal或者admin角色的用户可以访问
@PreAuthorize("hasAnyRole('normal','admin')")
//对于要求用户同时拥有normal和admin的话
@PreAuthorize("hasRole('normal') AND hasRole('admin')")
//在方法执行后再进行权限验证,适合验证带有返回值的权限
@PostAuthorize("returnObject != null && returnObject.username == authentication.name")