Spring是最受欢迎的企业级java应用程序开发框架,Spring最被人所认同的技术是控制反转的依赖注入(DI)模式。控制反转(Ioc)是一个通用的概念,它可以用许多种不同的方式去表达,而依赖注入仅仅是控制反转的一个具体的例子。除此之外Spring广为人知一个框架便是AOP,关于AOP的应用有很多不错的例子,如日志记录、声明性事务、安全性、和缓存等等。关于Spring的控制反转(Ioc)以及控制反转的依赖注入模式(DI)与Spring的关键组件面向方面的程序设计(AOP)框架这里就不做过多的阐述,有兴趣的小伙伴可以去看我关于Spring的专题。
SpringMVC框架是一个基于请求的驱动的web框架,并且使用了前端控制器的模型来进行设计,再根据映射规则分发给相应的页面控制器进行处理。
1.首先用户发送请求到前端控制器(DispatcherServlet),前端控制器根据请求信息(如URL)来决定选择哪一个页面控制器进行处理并把请求委托给它。图中的1、2步骤。
2.页面控制器收到请求后,进行功能处理,首先需要收集和绑定请求参数到一个对象,这个对象在Spring Web MVC中叫命令对象,并进行验证,然后将命令对象委托给业务对象进行处理,处理完毕后返回一个ModelAndView(模型数据和逻辑图名),图中的3、4、5步骤。
3.前端控制器收回控制权,然后根据返回的逻辑视图名选择相应的视图进行渲染,并把模型数据传入以便视图渲染。图中的6、7步骤。
4.前端控制器再次收回控制权,将响应返回给用户,至此请求过程中后端请求过程结束,图中的8步骤。
具体步骤:
第一步:发起请求到前端控制器(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的前身是Apache的开源项目iBatis。mybatis几乎可以代替JDBC,是一个支持普通SQl查询、存储过程和高级映射的基于java的优秀持久层框架。mybatis与JDBC相比,减少了50%以上的代码量。并且满足高并发和高响应的要求,所以它称为最流行的java互联网持久框架。
mybatis使用简单的XML或注解用于配置和原始映射,将接口和java的POJOs(Plain Old Java Objects,普通的java对象)映射成数据库中的记录 。关于mybatis的后续将会有相应的mybatis专栏,有兴趣的朋友可以前去指正一下。
在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三大框架整合之前先大概了解一下三大框架各自的作用,在整合思路里已经说过了,这里重新赘述一下,加深一下理解
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。
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:
4.0.0
com.myself.study
study-ssm
1.0-SNAPSHOT
war
study-ssm Maven Webapp
http://www.example.com
UTF-8
UTF-8
5.2.2.RELEASE
4.2.3.RELEASE
1.2
4.0.1
org.springframework
spring-core
${spring.version}
org.springframework
spring-web
${spring.version}
org.springframework
spring-webmvc
${spring.version}
jstl
jstl
${jstl.version}
javax.servlet
javax.servlet-api
4.0.1
provided
org.apache.logging.log4j
log4j-slf4j-impl
2.11.2
org.apache.logging.log4j
log4j-web
2.11.2
org.apache.logging.log4j
log4j-jcl
2.11.2
com.alibaba
fastjson
1.2.62
org.mybatis
mybatis
3.4.4
org.mybatis
mybatis-spring
1.3.0
org.springframework
spring-jdbc
5.2.2.RELEASE
mysql
mysql-connector-java
5.1.41
org.apache.shiro
shiro-core
1.5.2
org.apache.shiro
shiro-web
1.5.2
org.apache.shiro
shiro-spring
1.5.2
org.projectlombok
lombok
1.18.10
provided
com.fasterxml.jackson.core
jackson-databind
2.10.1
com.fasterxml.jackson.core
jackson-core
2.10.1
com.fasterxml.jackson.core
jackson-annotations
2.10.1
studyssm
src/main/resources
**/*.xml
**/*.properties
applicationContext.xml
/loginAdmin=anon
/admin*=authc
/student=roles[teacher]
/teacher=perms["user:create"]
spring-mvc.xml
mybatis-config.xml
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
/Users/danghongen/temporary/log
test.log
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
web.xml:
studySSM
shiroFilter
org.springframework.web.filter.DelegatingFilterProxy
targetFilterLifecycle
true
shiroFilter
/*
index.jsp
log4jConfiguration
classpath:conf/log4j2.xml
org.apache.logging.log4j.web.Log4jServletContextListener
contextConfigLocation
classpath:conf/applicationContext.xml
org.springframework.web.context.ContextLoaderListener
org.springframework.web.util.IntrospectorCleanupListener
springMvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:conf/spring-mvc.xml
1
springMvc
/
关于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
想学习的童鞋一定要自己手动搭建一遍,遇到问题可以留言给我!