Spring
Spring是最受欢迎的企业级java应用程序开发框架,Spring最被人所认同的技术是控制反转的依赖注入(DI)模式。控制反转(Ioc)是一个通用的概念,它可以用许多种不同的方式去表达,而依赖注入仅仅是控制反转的一个具体的例子。除此之外Spring广为人知一个框架便是AOP,关于AOP的应用有很多不错的例子,如日志记录、声明性事务、安全性、和缓存等等。关于Spring的控制反转(Ioc)以及控制反转的依赖注入模式(DI)与Spring的关键组件面向方面的程序设计(AOP)框架这里就不做过多的阐述,有兴趣的小伙伴可以去看我关于Spring的专题。
SpringMVC
SpringMVC框架是一个基于请求的驱动的web框架,并且使用了前端控制器的模型来进行设计,再根据映射规则分发给相应的页面控制器进行处理。
整体流程如下:
1.首先用户发送请求到前端控制器(DispatcherServlet),前端控制器根据请求信息(如URL)来决定选择哪一个页面控制器进行处理并把请求委托给它。图中的1、2步骤。
2.页面控制器收到请求后,进行功能处理,首先需要收集和绑定请求参数到一个对象,这个对象在Spring Web MVC中叫命令对象,并进行验证,然后将命令对象委托给业务对象进行处理,处理完毕后返回一个ModelAndView(模型数据和逻辑图名),图中的3、4、5步骤。
3.前端控制器收回控制权,然后根据返回的逻辑视图名选择相应的视图进行渲染,并把模型数据传入以便视图渲染。图中的6、7步骤。
4.前端控制器再次收回控制权,将响应返回给用户,至此请求过程中后端请求过程结束,图中的8步骤。
SpringMVC请求过程核心流程:
具体步骤:
第一步:发起请求到前端控制器(DispatcherServlet)
第二步:前端控制器请求处理器映射器(HandlerMapping)查找处理器(Handler)。注:可以根据xml配置、注解进行查找
第三步:处理器映射器(handlerMapping)向前端控制器返回处理器(Handler),HandlerMapping会把请求映射为HandlerExcutionChain对象(它包含一个Handler处理器(页面控制器)对象,多个HandlerInterceptor拦截器对象),通过这种策略模式,很容易添加新的映射策略。
第四步:前端控制器调用处理器适配器去执行Handler
第五步:处理器适配器(HandlerAdapter)将会根据适配的结果去执行Handler
第六步:Handler执行完成给适配器返回ModelAndView
第七步:处理器适配器向前端控制器返回ModelAndView(ModelAndView是SpringMvc框架的一个底层对象,包括Model和View)
第八步:前端控制器请求视图解析器去进行视图解析(根据逻辑视图名解析成真诚的视图(jsp)),通过这种策略很容易更换其他视图技术,只需要更改视图解析器即可。
第九步:视图解析器向前端控制器返回View
第十步:前端控制器进行视图渲染(视图渲染将模型数据(在ModelAndVies)填充到request域)
第十一步:前端控制器向用户响应结果。
核心开发步骤:
1.DispatcherServlet在web.xml中描述,从而拦截请求到Spring Web Mvc
2.HandlerMapping的配置,从而将请求映射到处理器
3.HandlerAdapter的配置,从而支持多种类型的处理器
注:处理器映射器和处理器适配器包含在注解驱动中,不需要再单独配置。
4.ViewResolver的配置,从而将逻辑视图名解析为具体视图技术
5.处理器(页面控制器)的配置,从而进行功能处理
View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf...)
Mybatis
mybatis的前身是Apache的开源项目iBatis。mybatis几乎可以代替JDBC,是一个支持普通SQl查询、存储过程和高级映射的基于java的优秀持久层框架。mybatis与JDBC相比,减少了50%以上的代码量。并且满足高并发和高响应的要求,所以它称为最流行的java互联网持久框架。
mybatis使用简单的XML或注解用于配置和原始映射,将接口和java的POJOs(Plain Old Java Objects,普通的java对象)映射成数据库中的记录 。关于mybatis的后续将会有相应的mybatis专栏,有兴趣的朋友可以前去指正一下。
SSM整合思路
在Spring中将各层进行整合
通过Spring管理持久层的mapper(相当于dao接口)
通过Spring管理业务层的service,service中可以调用mapper接口。
在Spring中进行事务控制
通过Spring管理表现层Controller,Controller中可以调用service接口。
mapper、service、Controller都是javabean,可以由Spring来进行统一管理。
基本思路:
第一步:整合dao
mybatis和spring整合,通过spring管理mapper接口。
使用mapper的扫描器自动扫描mapper接口在spring中进行注册。
第二步:整合service
通过Spring管理service接口。
使用配置方式将service接口配置在spring配置文件中。
实现事务控制。
第三步:整合springmvc
由于springmvc是spring的模块,不需要整合。
SSM整合
ssm使用图解
进行ssm三大框架整合之前先大概了解一下三大框架各自的作用,在整合思路里已经说过了,这里重新赘述一下,加深一下理解
1.SpringMVC:他用于web层,相当于Controller(等价于传统的servlet和struts的action),用来处理用户请求。举个例子用户在地址栏输入http://网站域名/login,那么springmvc就会拦截到这个请求,并且调用controller层中相应的方法(中间可能包含验证用户名密码和业务和逻辑,以及查询数据库操作,但这些都不是springmvc的职责),最终把结果返回给用户,并且返回相应的页面(当然也可以只返回json/xml等格式数据)。springmvc就是做前面和后面的活,与用户打交道。
2.Spring:关于spring与我们平常开发接触最多的就是IOC容器,他可以装载bean(也就是我们java中的类,当然也包括service 和dao里面的),有了这个机制我们就不用在每次使用这个类的时候为它初始化,很少看到关键字new。另外Spring的aop,事务管理等我们也是十分经常遇到。
3.MyBatis:如果你想问它跟那个大名鼎鼎的Hibernate有什么区别,我只能说mybatis更符合大多数人的需求。第一、他能自由控制sql,这会让有数据库经验的人编写的代码能够提高数据库访问的效率。第二、他可以使用xml的方式来组织管理sql,因为一般程序出错很多情况下是sql出错,别人接手代码后能够快速找到出错的地方,甚至可以优化原来写的sql。
第一步:创建maven工程
1.创建项目
2.选择maven——>Create from archetype——>选择如图模版
3.命名
这里着重说一下,GroupId是项目组织的唯一标识符,举个例子,如果你的公司名字叫做myself,有个项目叫做study,那么GroupId就应该是com.myself.study;而ArtifactedId则定义了当前项目在组中唯一的ID,比如study-ssm、study-shiro、study-redis等等。
填好了GroupId和ArtifactedId以后一直next,初次创建的时候生成比较慢,耐心等待就好了。生成项目如下:
第二步:创建目录
生成的项目只是很简单的项目结构,并不能满足我们的需求,所以我们要创建一些目录,如下:
目录介绍如下:
文件名 | 作用 |
src | 根目录,下面有main |
main | 主要目录,可以放java代码和一些资源文件。 |
java | 存放 Java 代码 |
com | java文件的子文件 |
myself | com文件的子文件 |
equipment | 区别于主程序的其他代码,如果没有,也可以不用创建 |
study | 存放主要的java代码 |
controller | 存放我们程序的接口代码也就是控制器,springmvc就是在这里发挥作用的 |
dao | 数据访问层:与数据打交道,可以是数据库操作,也可以是文件读写操作,甚至是redis缓存操作,总之与数据操作有关的都放在这里,在这里我们只需要写接口就可以,不用实现dao接口的实现类impl,因为我们使用的持久层框架是mybatis,可以在mapper中的xml配置文件中直接实现接口的方法。 |
entity | 实体类:一般来说与数据库的表相对应,封装dao层取出来的数据为对象,一般只在dao层与service层传输。 |
service | 业务逻辑层:在此处一般来处理我们的业务逻辑,controller直接调用它,将控制器层与逻辑层分开,有利于解耦合。 |
resources | 存放资源文件,如spring,springmvc,mybatis,日志、数据库等的配置文件。 |
conf | 存放程序的配置文件,一般存放spring,mybatis,日志、数据库等 |
applicationContext.xml | Spring的配置文件 |
generator.properties | mybatis中的代码自动生成功能的属性文件 |
generatorConfig.xml | mybatis中的代码自动生成功能的配置文件 |
jdbc.properties | 配置数据库的相关参数 |
log4j2.xml | 配置日志的相关参数 |
springmvc.xml | 配置springmvc的配置文件 |
mapper | 存放dao中每个方法对应的sql,故而dao不需要写方法的实现(impl) |
sql | sql文件中一般存放一些sql的脚本,比如数据库的表或者其他方面的改动。 |
system | system文件中可以放一些程序中用到的其他的properties文件,与conf中的properties文件区分开来,便于调用。 |
webapp | 存放前端的静态资源,比如jsp,js,css等 |
resources | 这里的resources存放项目的静态资源,比如js,css,image等 |
css | 存放css |
images | 存放iamge |
js | 存放js文件 |
WEB-INF | 很重要的一个目录,外部浏览器无法访问,只有项目内部才能访问,可以把jsp放在这里,另外就是web.xml了。你可能有疑问了,为什么上面java中的resources里面的配置文件不妨在这里,那么是不是会被外部窃取到?你想太多了,打包部署时候基本上只有webapp里面的静态资源如js、image、css等会直接输出到根目录,其他都会放入WEB-INF里面,项目内部依然可以使用classpath:XXX来访问,IDE里可以设置部署输出目录 |
jsp | 存放jsp代码 |
web.xml | 一个重要的但非必须配置文件,web.xml是用来配置欢迎页、servlet、filter等的,当你的web工程没用到这些的时候,你可以不用web.xml文件来配置你的web工程。 |
index.jsp | jsp进入网站默认的首页,也可以通过web.xml的配置来更改首页的jsp |
pom.xml | pom.xml是maven的配置文件,pom.xml主要描述了项目的maven坐标、依赖关系、开发者需要遵从的规则、组织和licenses、以及其他所有你的项目相关因素。是项目级别的配置文件。 |
接下来就进行ssm的整合,在整合的过程中同时整合了log4j2与shiro框架;
第三步:配置相关配置文件
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.myself.study</groupId>
<artifactId>study-ssm</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>study-ssm Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<!-- 设置项目编码编码 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- spring版本号 -->
<spring.version>5.2.2.RELEASE</spring.version>
<spring.security.version>4.2.3.RELEASE</spring.security.version>
<jstl.version>1.2</jstl.version>
<servlet.version>4.0.1</servlet.version>
</properties>
<dependencies>
<!--spring的三个核心依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<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>
<!--两个主要的页面依赖-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!--log4j2的三个依赖包-->
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.11.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-web -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-web</artifactId>
<version>2.11.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-jcl -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.11.2</version>
</dependency>
<!--json数据处理依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.4</version>
</dependency>
<!--mybatis整合spring依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<!--连接池-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.41</version>
</dependency>
<!--shiro的三个依赖包 -->
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.5.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-web -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.5.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.5.2</version>
</dependency>
<!-- lombomk-->
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
<!--Jackson 是当前用的比较广泛的,用来序列化和反序列化 json 的 Java 的开源框架,Spring MVC 的默认 json 解析器便是 Jackson,如果不引入该包在前台进行请求的时候
就会报错,因为后台无法解析发送的json数据-->
<!--
jackson-core,核心包,提供基于"流模式"解析的相关 API,它包括 JsonPaser 和 JsonGenerator。 Jackson 内部实现正是通过高性能的流模式 API 的 JsonGenerator 和 JsonParser 来生成和解析 json。
jackson-annotations,注解包,提供标准注解功能;
jackson-databind ,数据绑定包, 提供基于"对象绑定" 解析的相关 API ( ObjectMapper ) 和"树模型" 解析的相关 API (JsonNode);基于"对象绑定" 解析的 API 和"树模型"解析的 API 依赖基于"流模式"解析的 API。-->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.10.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.10.1</version>
</dependency>
</dependencies>
<build>
<finalName>studyssm</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
<!--mybatis-generator插件-->
<!--<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
<executions>
<execution>
<id>Generate MyBatis Artifacts</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
</plugin>
</plugins>-->
</build>
</project>
applicationContext.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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!--开启注解模式-->
<!--使用context:annotation-config/ 就可以隐式地自动向Spring容器注册4个BeanPostProcessor:
AutowiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
PersistenceAnnotationBeanPostProcessor
RequiredAnnotationBeanPostProcessor
这样就可以使用@ Resource 、@ PostConstruct、@ PreDestroy、@PersistenceContext、@Autowired、@Required等注解了,就可以实现自动注入。
注册这4个 BeanPostProcessor的作用,就是为了你的系统能够识别相应的注解。
-->
<context:annotation-config/>
<!--自动扫描除了Controller以外的注解-->
<context:component-scan base-package="com.myself.study">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--数据库连接池-->
<!--加载配置文件-->
<context:property-placeholder location="classpath:conf/jdbc.properties"/>
<!-- 配置数据源 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="123456"/>
</bean>
<!-- 配置mybatis的sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 自动扫描mappers.xml文件 -->
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
<!-- mybatis配置文件 -->
<property name="configLocation" value="classpath:conf/mybatis-config.xml"/>
</bean>
<!-- DAO接口所在包名,Spring会自动查找其下的类 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.myself.study.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
<!-- 配置自定义Realm -->
<bean id="myRealm" class="com.myself.study.service.realm.myRealm"/>
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myRealm"/>
</bean>
<!-- Shiro过滤器 核心-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- Shiro的核心安全接口,这个属性是必须的 -->
<property name="securityManager" ref="securityManager"/>
<!-- 身份认证失败,则跳转到登录页面的配置 -->
<property name="loginUrl" value="/login.jsp"/>
<!-- 权限认证失败,则跳转到指定页面 -->
<property name="unauthorizedUrl" value="/login.jsp"/>
<!-- Shiro连接约束配置,即过滤链的定义 -->
<property name="filterChainDefinitions">
<value>
<!--anon 表示匿名访问,不需要认证以及授权-->
/loginAdmin=anon
<!--authc表示需要认证 没有进行身份认证是不能进行访问的-->
/admin*=authc
/student=roles[teacher]
/teacher=perms["user:create"]
</value>
</property>
</bean>
<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<!-- 开启Shiro注解 -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor"/>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
</beans>
spring-mvc.xml
<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-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
<!-- 注解的映射器 -->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> -->
<!-- 注解的适配器 -->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> -->
<!-- 使用 mvc:annotation-driven可以代替上面注解映射器和注解适配器配置
mvc:annotation-driven默认加载了很多的参数绑定方法,比如json转换解析器就默认加载了
实际开发中使用mvc:annotation-driven
-->
<!-- 注解驱动:配置处理器映射器和适配器 -->
<mvc:annotation-driven/>
<!--springmvc容器中指定扫描controller注解,并且指定相应的包-->
<context:component-scan base-package="com.myself.study.controller">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 视图解析器
解析jsp解析,默认使用jstl标签,classpath下得有jstl的包
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--使用JSTL标签, 则指定InternalResourceViewResolver的viewClass属性为org.springframework.web.servlet.view.JstlView.-->
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<!-- 如果配置的有html视图解析器,则viewClass的值则配置为如下所示 -->
<!-- <property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/> -->
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/"/>
<!-- 后缀 -->
<property name="suffix" value=".jsp"/>
<property name="contentType" value="text/html;charset=UTF-8"/>
<!--配置优先等级,值越小等级越高-->
<property name="order" value="0"/>
</bean>
<!--静态资源映射-->
<mvc:resources mapping="/css/**" location="/resources/css/"/>
<mvc:resources mapping="/js/**" location="/resources/js"/>
</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>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!-- 扫描entity包,使用别名 -->
<typeAliases>
<package name="com.myself.study.entity"/>
</typeAliases>
<!-- 映射map -->
<mappers/>
</configuration>
jdbc.properties
driver=com.mysql.jdbc.Driver
#mytest为我本地的数据库名
url=jdbc:mysql://localhost:3306/ssm?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8
username=root
#下面输入自己数据库的密码
password=123456
#定义初始连接数
initialSize=0
#定义最大连接数
maxActive=20
#定义最大空闲
maxIdle=20
#定义最小空闲
minIdle=1
#定义最长等待时间
maxWait=60000
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--status="WARN" :用于设置log4j2自身内部日志的信息输出级别,默认是OFF-->
<!--monitorInterval="30" :间隔秒数,自动检测配置文件的变更和重新配置本身-->
<configuration status="WARN" monitorInterval="0">
<Properties>
<!--自定义一些常量,之后使用${变量名}引用-->
<Property name="logFilePath">/Users/danghongen/temporary/log</Property>
<Property name="logFileName">test.log</Property>
</Properties>
<!--appenders:定义输出内容,输出格式,输出方式,日志保存策略等,常用其下三种标签[console,File,RollingFile]-->
<appenders>
<!--console :控制台输出的配置-->
<console name="Console" target="SYSTEM_OUT">
<!--PatternLayout :输出日志的格式,LOG4J2定义了输出代码,详见第二部分-->
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
</console>
<!--File :同步输出日志到本地文件-->
<!--append="false" :根据其下日志策略,每次清空文件重新输入日志,可用于测试-->
<File name="log" fileName="${logFilePath}/${logFileName}" append="false">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
</File>
<!--SMTP :邮件发送日志-->
<!--<SMTP name="Mail" subject="****SaaS系统正式版异常信息" to="message@message.info" from="message@lengjing.info" smtpUsername="message@message.info" smtpPassword="LENG****1234" smtpHost="mail.lengjing.info" smtpDebug="false" smtpPort="25" bufferSize="10">
<PatternLayout pattern="[%-5p]:%d{YYYY-MM-dd HH:mm:ss} [%t] %c{1}:%L - %msg%n" />
</SMTP>-->
<!-- ${sys:user.home} :项目路径 -->
<RollingFile name="RollingFileInfo" fileName="${logFilePath}/logs/info.log"
filePattern="${logFilePath}/logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log">
<!--ThresholdFilter :日志输出过滤-->
<!--level="info" :日志级别,onMatch="ACCEPT" :级别在info之上则接受,onMismatch="DENY" :级别在info之下则拒绝-->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
<!-- Policies :日志滚动策略-->
<Policies>
<!-- TimeBasedTriggeringPolicy :时间滚动策略,默认0点小时产生新的文件,interval="6" : 自定义文件滚动时间间隔,每隔6小时产生新文件, modulate="true" : 产生文件是否以0点偏移时间,即6点,12点,18点,0点-->
<TimeBasedTriggeringPolicy interval="6" modulate="true"/>
<!-- SizeBasedTriggeringPolicy :文件大小滚动策略-->
<SizeBasedTriggeringPolicy size="100 MB"/>
</Policies>
<!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 -->
<DefaultRolloverStrategy max="20"/>
</RollingFile>
<RollingFile name="RollingFileWarn" fileName="${logFilePath}/logs/warn.log"
filePattern="${logFilePath}/logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log">
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="100 MB"/>
</Policies>
</RollingFile>
<RollingFile name="RollingFileError" fileName="${logFilePath}/logs/error.log"
filePattern="${logFilePath}/logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log">
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="100 MB"/>
</Policies>
</RollingFile>
</appenders>
<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
<loggers>
<!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
<!--Logger节点用来单独指定日志的形式,name为包路径,比如要为org.springframework包下所有日志指定为INFO级别等。 -->
<!--<logger name="org.springframework" level="INFO"></logger>
<logger name="org.mybatis" level="INFO"></logger>-->
<!-- Root节点用来指定项目的根日志,如果没有单独指定Logger,那么就会默认使用该Root日志输出 -->
<root level="all">
<appender-ref ref="Console"/>
<appender-ref ref="RollingFileInfo"/>
<appender-ref ref="RollingFileWarn"/>
<appender-ref ref="RollingFileError"/>
</root>
<!--AsyncLogger :异步日志,LOG4J有三种日志模式,全异步日志,混合模式,同步日志,性能从高到底,线程越多效率越高,也可以避免日志卡死线程情况发生-->
<!--additivity="false" : additivity设置事件是否在root logger输出,为了避免重复输出,可以在Logger 标签下设置additivity为”false”-->
<!--<AsyncLogger name="AsyncLogger" level="trace" includeLocation="true" additivity="false">
<appender-ref ref="RollingFileError"/>
</AsyncLogger>-->
</loggers>
</configuration>
generator.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf-8
username=root
password=123456
#entity 包名和 java目录
modelPackage=com.myself.study.entity
modelProject=src/main/java
#sqlmap包名 和resources目录
sqlPackage=mapper
sqlProject=src/main/resources
#mapper包名和 java目录
mapperPackage=com.myself.study.dao
mapperProject=src/main/java
generatorConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!--导入属性配置 -->
<properties resource="generator.properties"/>
<classPathEntry
location="/Users/danghongen/develop/maven/repository/mysql/mysql-connector-java/5.1.41/mysql-connector-java-5.1.41.jar" />
<context id="context1">
<!-- 注释 -->
<commentGenerator>
<property name="suppressAllComments" value="true" /><!-- 是否取消注释 -->
<property name="suppressDate" value="true" /> <!-- 是否生成注释代时间戳 -->
</commentGenerator>
<jdbcConnection driverClass="${driver}"
connectionURL="${url}"
userId="${username}"
password="${password}" />
<!-- 类型转换 -->
<javaTypeResolver>
<!-- 是否使用bigDecimal, false可自动转化以下类型(Long, Integer, Short, etc.) -->
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!--生成entity的包名和位置-->
<javaModelGenerator targetPackage="${modelPackage}" targetProject="${modelProject}">
<!-- 在targetPackage的基础上,根据数据库的schema再生成一层package,最终生成的类放在这个package下,默认为false -->
<property name="enableSubPackages" value="false"/>
<!-- 设置是否在getter方法中,对String类型字段调用trim()方法-->
<property name="trimStrings" value="false"/>
</javaModelGenerator>
<!--生成映射文件的包名和位置-->
<sqlMapGenerator targetPackage="${sqlPackage}" targetProject="${sqlProject}">
<!-- 在targetPackage的基础上,根据数据库的schema再生成一层package,最终生成的类放在这个package下,默认为false -->
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<!--生成mapper(也可叫做dao)的包名和位置-->
<javaClientGenerator targetPackage="${mapperPackage}" targetProject="${mapperProject}" type="XMLMAPPER">
<!-- 在targetPackage的基础上,根据数据库的schema再生成一层package,最终生成的类放在这个package下,默认为false -->
<property name="enableSubPackages" value="false"/>
</javaClientGenerator>
<!--要生成的表 tableName是数据库中的表名或视图名 domainObjectName是实体类名,如果需要通配所有表 直接用sql的通配符 %即可 -->
<table schema="" tableName="%" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>
</context>
</generatorConfiguration>
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd_0.xsd">
<display-name>studySSM</display-name>
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<!-- 该值缺省为false,表示声明周期由SpringApplicationContext管理,设置为true表示ServletContainer管理 -->
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!--log4j文件配置-->
<context-param>
<param-name>log4jConfiguration</param-name>
<!--默认是classpath下的log4j2.xml-->
<param-value>classpath:conf/log4j2.xml</param-value>
</context-param>
<!--log4j的监听器要放在Spring监听器前面-->
<listener>
<listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class>
</listener>
<!-- 启动Spring 配置spring容器相关的资源文件和创建容器的监听-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
<!-- 配置springmvc的前端控制器 指向spring-mvc.xml 程序在启动的时候就加载springmvc 可以接受所有请求 load-on-startup:表示启动容器时初始化该Servlet; -->
<servlet>
<servlet-name>springMvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 可以自定义servlet.xml配置文件的位置和名称, 默认为WEB-INF目录下,名称为[<servlet-name>]-servlet.xml,如spring-servlet.xml -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value> classpath:conf/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 将前端URL请求和后台处理方法controller建立对应关系-->
<servlet-mapping>
<servlet-name>springMvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
关于ssm与shiro整合主要是realm的重写,重写的realm名字为myRealm类,该类需要继承AuthorizingRealm并重写doGetAuthorizationInfo()方法与doGetAuthenticationInfo()方法;如下所示:
myRealm.java
package com.myself.study.service.realm;
import com.myself.study.entity.SysUser;
import com.myself.study.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Arrays;
public class myRealm extends AuthorizingRealm {
// 注解Resource与Autowired类似但不相同
@Autowired
UserService userService;
/**
* 为当前登录成功的用户授予权限和角色,已经登录成功了
*/
/*参数解释:
* PrincipalCollection:是一个身份集合,而方法getPrimaryPrincipal则是得到主要的身份,需要注意的是,如果只有一个Principal则直接返回,如果有多个,则返回第一个(因为内部使用map储存,所以可以认为是返回任意一个)
* SimpleAuthorizationInfo:用于聚合授权信息
* */
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String username=(String) principalCollection.getPrimaryPrincipal();//获取用户名
SimpleAuthorizationInfo authenticationInfo=new SimpleAuthorizationInfo();
authenticationInfo.setRoles(userService.getRoles(username));//set角色字符串信息
authenticationInfo.setStringPermissions(userService.getPermissions(username));//set权限字符串信息
return authenticationInfo;
}
/**
* 验证当前登陆的用户,获取认证信息
*/
/*参数解释:
* AuthenticationToken:AuthenticationToken 用于收集用户提交的身份(如用户名)及凭据(如密码)
*AuthenticationInfo:AuthenticationInfo对象中存储的是主体(Subject)的身份认证信息。Shiro会调用CredentialsMatcher对象的doCredentialsMatch方法
对AuthenticationInfo对象和AuthenticationToken进行匹配。匹配成功则表示主体(Subject)认证成功,否则表示认证失败。。
*在认证成功以后进行权限与角色的查询,需要创建SimpleAuthenticationInfo对象。
* SimpleAuthenticationInfo:SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
userInfo, //用户名–此处传的是用户对象
userInfo.getPassword(), //密码—从数据库中获取的密码
salt,//盐–用于加密密码对比,–获取的经验:为了防止两用户的初始密码是一样的,
四个参数,防止两用户可能初始密码相同时候用,token 用simplehash(四个参数的构造) 加密默认用了MD5 迭代一次加密,
info中在密码比对调用new SimpleHash(String algorithmName, Object source)这个实例化对象默认迭代一次了,
所以当你用三个参数加密时候可能两 个初始密码相同人的就没能区别开 (因此realm中密码要从数据库的查的原因),通过设置reaml 中credentialsMatcher 属性的各项属性可实现
getName() //当前的realm名
); */
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token= (UsernamePasswordToken) authenticationToken;
String username=token.getUsername();//获取用户名
String password= Arrays.toString(token.getPassword());
SysUser user=userService.getByUsername(username);
if (user!=null){
if (!password.equals(user.getPassword())){
return new SimpleAuthenticationInfo(user.getUserName(),user.getPassword(),"myRealm");
}else {
throw new AccountException("密码错误!");
}
}else {
throw new AccountException("账号不存在");
}
}
}
以上是我整合完成后的配置文件,在整合的过程中还遇到过很多问题,我专门写了一篇问题集锦,以及相应的源码地址以及数据库的sql文件!
文章地址如下:https://blog.csdn.net/weixin_40159122/article/details/105507947
源码地址如下(附带数据库的SQL文件):https://github.com/danghongen/study-ssm
想学习的童鞋一定要自己手动搭建一遍,遇到问题可以留言给我!