SSM 架构基础
一、简介
Spring 框架是 Java 应用最广的框架,它的成功来源于理念,而不是技术本身,spring框架是一个为Java应用程序的开发提供了综合、广泛的基础性支持的Java平台。
spring主要的核心依赖有 beans,code, context,spel 这是spring里最基本的也是最核心的jar包(或者说是依赖)
spring有两个核心思想:IOC (控制反转) , AOP(面向切面编程)
spring容器可以理解为生产对象(OBJECT)的地方,在这里容器不只是帮我们创建了对象那么简单,它负责了对象的整个生命周期--创建、装配、销毁。
而这里对象的创建管理的控制权都交给了Spring容器,所以这是一种控制权的反转,称为IOC容器,而这里IOC容器不只是Spring才有,很多框架也都有该技术。
springmvc是spring的子框架,继承于spring框架 , 在ssm框架环境中,springmvc可以向上的扫描去用spring的东西,但是spring却不能扫描到springmvc里面去。
springmvc也是接收请求,返回响应 ,实际上也是一个servlet ,dispatchServlet。
springmvc和servlet的流程是差不多的,都是接受请求,返回响应,和 Sping 无缝结合
mybatis是目前非常流行的持久层框架,功能很强大,然而其实现却比较简单、优雅。mybatis是一个半自动的orm框架,也还是需要自己去写sql语句
mybatis是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架,其主要就完成2件事情:
- 封装JDBC操作
- 利用反射打通Java类与SQL语句之间的相互转换
mybatis的主要设计目的就是让我们对执行SQL语句时对输入输出的数据管理更加方便,所以方便地写出SQL和方便地获取SQL的执行结果才是MyBatis的核心竞争力。
mybatis和大部分框架一样需要一个配置文件,如果是和spring整合的话则不怎么需要,当然如果要开启缓存的话还是需要
然后需要mapper映射文件和dao层的类和方法所对应 , 在mapper里面写sql语句
单独的mybatis使用需要解析配置文件,然后去调用mapper里的sql语句
二、Spring
2.1 Spring xml写法
原始类:
public class Source { private String property01; private String property02; /* setter and getter */ }
bean.xml 文件:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="source" class="pojo.Source">
<property name="property01" value="v01"/>
<property name="property02" value="v02"/>
</bean>
</beans>
测试类
public class TestSpring { @Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext( new String[]{"applicationContext.xml"} ); Source source = (Source) context.getBean("source"); System.out.println(source.property01()); System.out.println(source.property02()); } }
ApplicationContext 是 BeanFactory 的子接口之一,换句话说:BeanFactory 是 Spring IoC 容器所定义的最底层接口,而 ApplicationContext 是其最高级接口之一,并对 BeanFactory 功能做了许多的扩展,所以在绝大部分的工作场景下,都会使用 ApplicationContext 作为 Spring IoC 容器。
如果说BeanFactory是Sping的心脏,那么ApplicationContext就是完整的身躯了
2.2 通过注解装配 Bean
传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop、事物,这么做有两个缺点:
- 如果所有的内容都配置在.xml文件中,那么.xml文件将会十分庞大;如果按需求分开.xml文件,那么.xml文件又会非常多。总之这将导致配置文件的可读性与可维护性变得很低
- 在开发中在.java文件和.xml文件之间不断切换,是一件麻烦的事,同时这种思维上的不连贯也会降低开发的效率
为了解决这两个问题,Spring引入了注解,通过"@XXX"的方式,让注解与Java Bean紧密结合,既大大减少了配置文件的体积,又增加了Java Bean的可读性与内聚性。
@Component(value = "source1") public class Source { @Value("1") int id; @Value("student_name_1") String name; // getter and setter }
@Component
把普通pojo实例化到spring容器中,相当于配置文件中的 <bean id="" class=""/>
@Component是一个元注解,意思是可以注解其他类注解,如@Controller @Service @Repository @Aspect。
官方的原话是:带此注解的类看为组件,当使用基于注解的配置和类路径扫描的时候,这些类就会被实例化。
其他类级别的注解也可以被认定为是一种特殊类型的组件,比如@Repository @Aspect。所以,@Component可以注解其他类注解。
@Autowired (自动装配)注释可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 其作用是为了消除代码Java代码里面的getter/setter与bean属性中的property。@Autowired 根据类型(type)进行自动注入,默认注入单例(SingleTon)的bean。就是一个。
如果发现找到有很多bean,则按照byName方式对比获取,若有名称一样的则可以加上@Qualifier("XXX")配置使用。若非必须装配则可以设置required=false。
@Component("studentService") public class StudentServiceImp implements StudentService { @Autowired private Student source = null; public void printStudentInfo() { System.out.println(source.getName()); } }
@Configuration @Bean 注解
@Bean 注解 可以标记在方法和注解上面,主要标记在方法上.被标记的方法的返回值会被加入到springIOC容器之中
使用 @Bean 注解的好处就是能够动态获取一个 Bean 对象,能够根据环境不同得到不同的 Bean 对象。或者说将 Spring 和其他组件分离(其他组件不依赖 Spring,但是又想 Spring 管理生成的 Bean)
@Configuration public class AppConfig { @Bean public TransferService transferService() { return new TransferServiceImpl(); } }
这个配置就等同于之前在xml里的配置
<beans> <bean id="transferService" class="com.acme.TransferServiceImpl"/> </beans>
2.3 AOP
AOP技术利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
第一步:选择连接点
Spring 是方法级别的 AOP 框架,我们主要也是以某个类额某个方法作为连接点,另一种说法就是:选择哪一个类的哪一方法用以增强功能。
public void service() { // 核心的业务功能 System.out.println("签合同"); System.out.println("收房租"); }
第二步:创建切面
@Component @Aspect class Broker { @Before("execution(* pojo.Landlord.service())") public void before(){ System.out.println("带租客看房"); System.out.println("谈价格"); } @After("execution(* pojo.Landlord.service())") public void after(){ System.out.println("交钥匙"); } }
第三步:定义切点
@Component @Aspect class Broker { @Pointcut("execution(* pojo.Landlord.service())") public void lService() { } @Before("lService()") public void before() { System.out.println("带租客看房"); System.out.println("谈价格"); } @After("lService()") public void after() { System.out.println("交钥匙"); } }
第四步:测试 AOP
三、SpringMVC
3.1 运行原理:
(1) Http请求:客户端请求提交到DispatcherServlet。
(2) 寻找处理器:由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的Controller。
(3) 调用处理器:DispatcherServlet将请求提交到Controller。
(4)(5)调用业务处理和返回结果:Controller调用业务逻辑处理后,返回ModelAndView。
(6)(7)处理视图映射并返回模型: DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定视图
(8) Http响应:视图负责将结果显示到客户端。
接口:
(1)DispatcherServlet接口:
Spring提供的前端控制器,所有的请求都有经过它来统一分发。在DispatcherServlet将请求分发给Spring Controller之前,需要借助于Spring提供的HandlerMapping定位到具体的Controller。
(2)HandlerMapping接口:
能够完成客户请求到Controller映射。
(3)Controller接口:
需要为并发用户处理上述请求,因此实现Controller接口时,必须保证线程安全并且可重用。
Controller将处理用户请求,这和Struts Action扮演的角色是一致的。一旦Controller处理完用户请求,则返回ModelAndView对象给DispatcherServlet前端控制器,ModelAndView中包含了模型(Model)和视图(View)。
从宏观角度考虑,DispatcherServlet是整个Web应用的控制器;从微观考虑,Controller是单个Http请求处理过程中的控制器,而ModelAndView是Http请求过程中返回的模型(Model)和视图(View)。
(4)ViewResolver接口:
Spring提供的视图解析器(ViewResolver)在Web应用中查找View对象,从而将相应结果渲染给客户。
DispatcherServlet:
整个Spring MVC的核心。它负责接收HTTP请求组织协调Spring MVC的各个组成部分。其主要工作有以下三项:
- 截获符合特定格式的URL请求。
- 初始化DispatcherServlet上下文对应WebApplicationContext,并将其与业务层、持久化层的WebApplicationContext建立关联。
- 初始化Spring MVC的各个组成组件,并装配到DispatcherServlet中。
3.2 传统方式:
dispatcher-servlet.xml
<bean id="simpleUrlHandlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<!-- /hello 路径的请求交给 id 为 helloController 的控制器处理-->
<prop key="/hello">helloController</prop>
</props>
</property>
</bean>
<bean id="helloController" class="controller.HelloController"></bean>
</beans>
Controller:
public class HelloController implements Controller { public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception { ModelAndView mav = new ModelAndView("index.jsp"); mav.addObject("message", "Hello Spring MVC"); return mav; } }
View: index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false"%>
<h1>${message}</h1>
3.3 使用注解配置 Spring MVC
Controller:
@Controller public class HelloController{ @RequestMapping("/hello") public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception { ModelAndView mav = new ModelAndView("index.jsp"); mav.addObject("message", "Hello Spring MVC"); return mav; } }
使用 @Controller 注解,在对应的方法上,视图解析器可以解析return 的jsp,html页面,并且跳转到相应页面
若返回json等内容到页面,则需要加@ResponseBody注解,@RestController注解相当于@ResponseBody + @Controller合在一起的作用
使用@RequestMapping 注解映射请求路径,@RequestMapping 既可以定义在类上,也可以定义方法上
dispatcher-servlet.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"
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">
<!-- 扫描controller下的组件 -->
<context:component-scan base-package="controller"/>
</beans>
<!-- 配置视图解析器 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/page/" />
<property name="suffix" value=".jsp" />
</bean>
数据显示
@RequestMapping("hello") public String testVelocity(Model model,String name){ model.addAttribute("name",name); return "hello"; } @RequestMapping("model") public ModelAndView testModel(String name) { //构建ModelAndView实例,并设置跳转地址 ModelAndView view = new ModelAndView("test"); //将数据放置到ModelAndView对象view中,第二个参数可以是任何java类型 view.addObject("name",name); //返回ModelAndView对象view return view; }
跳转:
@RequestMapping("/jump") public String jump() { return "redirect: ./hello"; }
四、MyBatis
4.1 基本配置
数据库配置文件: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> <!-- 别名 --> <typeAliases> <package name="pojo"/> </typeAliases> <!-- 数据库环境 --> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <!-- 映射文件 --> <mappers> <mapper resource="pojo/Student.xml"/> </mappers> </configuration>
Mapper 文件:StudentMapper.xml
<?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="pojo">
<select id="listStudent" resultType="Student">
select * from student
</select>
<insert id="addStudent" parameterType="Student">
insert into student (id, studentID, name) values (#{id},#{studentID},#{name})
</insert>
<delete id="deleteStudent" parameterType="Student">
delete from student where id = #{id}
</delete>
<select id="getStudent" parameterType="_int" resultType="Student">
select * from student where id= #{id}
</select>
<update id="updateStudent" parameterType="Student">
update student set name=#{name} where id=#{id}
</update>
</mapper>
测试类
public class TestMyBatis {
public static void main(String[] args) throws IOException {
// 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 然后根据 sqlSessionFactory 得到 session
SqlSession session = sqlSessionFactory.openSession();
// 增加学生
Student student1 = new Student();
student1.setId(4);
student1.setStudentID(4);
student1.setName("新增加的学生");
session.insert("addStudent", student1);
// 删除学生
Student student2 = new Student();
student2.setId(1);
session.delete("deleteStudent", student2);
// 获取学生
Student student3 = session.selectOne("getStudent", 2);
// 修改学生
student3.setName("修改的学生");
session.update("updateStudent", student3);
// 最后通过 session 的 selectList() 方法调用 sql 语句 listStudent
List listStudent = session.selectList("listStudent");
for (Student student : listStudent) {
System.out.println("ID:" + student.getId() + ",NAME:" + student.getName());
}
// 提交修改
session.commit();
// 关闭 session
session.close();
}
}
应用程序找 MyBatis 要数据 MyBatis 从数据库中找来数据
1.通过 mybatis-config.xml 定位哪个数据库
2.通过 Student.xml 执行对应的 sql 语句
3.基于 Student.xml 把返回的数据库封装在 Student 对象中
4.把多个 Student 对象装载一个 Student 集合中
4.2 使用注解开发 MyBatis
为 Mapper 增加注解:
public interface StudentMapper { // 根据 id 查询学生信息 @Select("SELECT * FROM student WHERE student_id = #{id}") public Student findStudentById(int id) throws Exception; // 添加学生信息 @Insert("INSERT INTO student(student_id, name) VALUES(#{id}, #{name})") public void insertStudent(Student student) throws Exception; // 删除学生信息 @Delete("DELETE FROM student WHERE student_id = #{id}") public void deleteStudent(int id) throws Exception; // 修改学生信息 @Update("UPDATE student SET name = #{name} WHERE student_id = #{id}") public void updateStudent(Student student) throws Exception; }
mybatis-config.xml:
<mappers>
<!--<mapper resource="pojo/StudentMapper.xml"/>-->
<mapper class="mapper.StudentMapper"/>
</mappers>
四、Spring+SpringMVC+MyBatis (Maven)
4.1 创建SqlMapperContext.xml全局配置文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://www.mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <typeAliases> <package name="com.fjm.ssm.po"/> </typeAliases> </configuration>
4.2 Spring 和 Mybatis 配置:
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" 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">
<!-- 配置数据库相关参数properties的属性:${url} -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 数据库连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxPoolSize" value="${c3p0.maxPoolSize}"/>
<property name="minPoolSize" value="${c3p0.minPoolSize}"/>
<property name="autoCommitOnClose" value="${c3p0.autoCommitOnClose}"/>
<property name="checkoutTimeout" value="${c3p0.checkoutTimeout}"/>
<property name="acquireRetryAttempts" value="${c3p0.acquireRetryAttempts}"/>
</bean>
<!-- 配置SqlSessionFactory对象 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource"/>
<!-- 扫描entity包 使用别名 -->
<property name="typeAliasesPackage" value="cn.wmyskxz.entity"/>
<!-- 扫描sql配置文件:mapper需要的xml文件 -->
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
<!-- 配置扫描Dao接口包,动态实现Dao接口,注入到spring容器中 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入sqlSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!-- 给出需要扫描Dao接口包 -->
<property name="basePackage" value="cn.wmyskxz.dao"/>
</bean>
</beans>
4.3 Spring Service 配置:
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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 扫描service包下所有使用注解的类型 -->
<context:component-scan base-package="cn.wmyskxz.service"/>
<!--配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 传播特性 -->
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="del*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="modify*" propagation="REQUIRED" />
<tx:method name="find*" read-only="true" />
<tx:method name="query*" read-only="true" />
<tx:method name="select*" read-only="true" />
<tx:method name="get*" read-only="true" />
</tx:attributes>
</tx:advice>
<!--配置切面 -->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.fjm.ssm.service.*.*(..))"/>
</aop:config>
</beans>
4.4 Spring MVC 的相关配置
spring-mvc.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">
<!-- 扫描web相关的bean -->
<context:component-scan base-package="cn.wmyskxz.controller"/>
<!-- 开启SpringMVC注解模式 -->
<mvc:annotation-driven/>
<!-- 静态资源默认servlet配置 -->
<mvc:default-servlet-handler/>
<!-- 配置jsp 显示ViewResolver -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
4.5 jdbc.properties 中配置数据库连接池
6
jdbc.driver=com.mysql.jdbc.Driver #数据库地址 jdbc.url=jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf8 #用户名 jdbc.username=root #密码 jdbc.password=root #最大连接数 c3p0.maxPoolSize=30 #最小连接数 c3p0.minPoolSize=10 #关闭连接后不自动commit c3p0.autoCommitOnClose=false #获取连接超时时间 c3p0.checkoutTimeout=10000 #当获取连接失败重试次数 c3p0.acquireRetryAttempts=2
4.6 创建接口和实现类,调用 mapper 接口实现数据调用
@Service public class ItemsServiceImpl implements ItemsService { @Autowired private ItemsExtMapper mapper; @Override public List<Items> queryItemsByItemsQuery(ItemsQuery vo) { return mapper.ItemsQuery(vo); } }
参考:
https://www.cnblogs.com/wmyskxz/p/8916365.html
https://www.cnblogs.com/fengjunming/p/7583229.html