GPT摘要
本文主要介绍了Spring框架的几个核心概念和技术,包括IOC(控制反转)和DI(依赖注入)、AOP(面向切面编程)、Spring对MyBatis的整合以及SpringMVC的基础知识。  1. IOC和DI    - IOC将对象的创建权交给Spring工厂,通过配置文件管理对象的创建和依赖关系。DI维护对象之间的关系,通常通过setter方法或构造器注入实现。  2. AOP    - AOP的底层原理是动态代理,用于实现如日志、事务等横切关注点。AOP通过定义切面(通知+切入点)来实现对特定方法的增强。  3. Spring整合MyBatis    - Spring通过SqlSessionFactoryBean和MapperScannerConfigurer简化了MyBatis的配置,实现了对MyBatis的整合管理。  4. 声明式事务    - 使用DataSourceTransactionManager和@Transactional注解实现事务管理,保证了数据操作的原子性和一致性。  5. SpringMVC    - SpringMVC通过DispatcherServlet统一处理请求,配合视图解析器和控制器实现MVC模式。提供了灵活的请求映射和数据绑定机制。  总结来看,Spring框架通过IOC和AOP等核心技术,结合对MyBatis和MVC的支持,提供了一个强大且灵活的企业级应用开发平台。其模块化设计和丰富的集成能力大大简化了Java EE应用的开发复杂度。
Spring
1.IOC and DI
	将new的权力交给spring,由工厂提供对象,同时通过DI维护对象与对象之间的关系
2.AOP
	底层原理:动态代理的封装
	通过产生动态代理来实现附加操作,来减少代码冗余
	切面 = 通知(额外功能) + 切入点(加在哪里,哪些service类的哪些方法)
	通知和切入点可以随意组合成切面
1. 引言
项目管理框架,不是替换别的框架,而是将框架进行整合管理
对组件(controller service Dao )进行对象管理(创建 使用 销毁),entity通常不交给spring
| 12
 3
 4
 
 | 原来: new 去创建,然后调用userDao = new UserDaoImpl();
 userDao.save()
 现在:xml配置bean,然后直接取出来
 
 | 
- 导入依赖   org.springframework下的spring-webmvc 
- 配置applicationContext.xml - bean来管理对象的创建,class指定类UserDaoImpl,id唯一标识在spring容器中取出来(最好首字母小写) | 1
 | <bean id="userDao" class="init.UserDaoImpl"></bean>
 |  
 
- 启动工程,绑定xml文件,取出bean 
| 12
 3
 4
 5
 
 | public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("init/applicationContext.xml");
 UserDao usertest = (UserDao)context.getBean("userDao");
 usertest.save("小明");
 }
 
 | 
2. 核心思想
- IOC(Inversion of Control)控制反转         - 由手动new变为配置文件配置,交给spring工厂。在tomcat中,也是该思想帮助我们创建了response对象 - 原理Class.forName(“UserDaoImpl”).newInstance()   反射调用构造方法 
- AOP面向切面 
DI:dependency Injection    IOC的补充
	存在嵌套service调用dao,也就是serviceImpl中需要拿到daoImpl。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | public class UserServiceImpl implements UserService{private UserDao userDao;
 
 public void setUserDao(UserDao userDao) {
 this.userDao = userDao;
 }
 
 @Override
 public void save(String name) {
 userDao.save(name);
 }
 }
 
 | 
	都要先声明一个成员对象,然后 
			原来:new UserDaoImpl();
			现在:需要set方法,在配置中完成赋值操作(注入)      set注入
| 12
 3
 4
 5
 
 | ref:工程里的标识 bean的id,name:注入哪个属性<bean id="userService" class="userServiceImpl">
 <property name="userDao" ref="userDao" />
 </bean>
 
 
 | 
IOC 创建对象,DI 维护对象与对象之间的关系
3. 注入
除了一个对象的注入,其他的用的很少
- set 注入    	property标签
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 
 | 1. 对象注入 ref<property name="userDao" ref="userDao" />
 2. String、日期、八种基本类型 value注入
 <property name="name" value="xiao"></property>
 <property name="data" value="2012/12/12 23:54:57"></property>  日期需要/ :格式
 3. array list set
 <property name="hobbys">
 <array> 这里不同
 <value>听歌</value>  字符串用value
 <ref bean="userDao"></value>  类用ref
 </array>
 </property>
 map
 <property name="card">
 <map>
 <entry key="1" value="123"></entry>
 <entry key-ref="userDao" key-ref="userDao"></entry> 类
 </map>
 </property>
 properties  无序键值对集合
 <property name="info">
 <props>
 <prop key="driver">com.mysqljdbc.Driver</prop>
 <prop key="姓名">jdbc:mysql://localhost:3306/test</prop>
 </props>
 </property>
 
 | 
- 构造注入       constructor-arg 标签
| 12
 3
 4
 
 | 使用公开的有参构造方法  index代表参数的位置<constructor-arg index="0" name="name" value="小明"/>
 
 如果想单独赋值某些元素,就要对应的构造方法,很麻烦!!
 
 | 
- 自动注入      autowire = ”byType“  “byName”
底层是set  需要在组件标签上开启
Autowired 属于 Spring 内置的注解,默认的注入方式为byType(根据类型进行匹配),也就是说会优先根据接口类型去匹配并注入 Bean (接口的实现类)。
问题: 当一个接口存在多个实现类的话,byType这种方式就无法正确注入对象了
这种情况下,注入方式会变为 byName(根据名称进行匹配),这个名称通常就是类名(首字母小写)。
SmsService 接口有两个实现类: SmsServiceImpl1和 SmsServiceImpl2,且它们都已经被 Spring 容器所管理。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | @Autowired
 private SmsService smsService;
 
 @Autowired
 private SmsService smsServiceImpl1;
 
 
 @Autowired
 @Qualifier(value = "smsServiceImpl1")
 private SmsService smsService;
 
 | 
4.  工厂特征
默认单例,多次getBean还是同一个。 struct2用成员对象存储信息,所以这时要多例   bean中scope = “prototype”
原理: 反射 + 构造方法
生命周期
单例:工厂启动时创建,正常关闭工程时销毁 context.close()
多例:getBean时创建,创建完成后脱离spring的管理,jvm去销毁
| 12
 
 | 自己写的方法init-method="" destroy-method=""
 
 | 
好处:
- 解耦合,更换类只需要修改配置文件
- 减少内存占用
- 建立对象与对象之间的关系   打开配置文件就可看到
5. 代理
代理对象:完成传化,也可以附加操作,同时也可以中断
		好处:原始业务逻辑不变,同时可以附加
- 代理对象和原始逻辑对象实现相同的接口
- 代理对象 依赖 原始业务逻辑对象
原始逻辑中,除了具体事务,还有开启事务、提交事务、回滚事务的方法。后面这部分是重复的
在代理中,负责处理这些额外的方法,同时需要调用原始对象。总体的处理逻辑不变
| 12
 3
 4
 5
 
 | public void save(){sout("开启事务")
 userService.save(name)
 out("结束事务")
 }
 
 | 
静态代理
每一个业务对象都开发一个代理对象,上面的逻辑
动态代理
在程序运行中自动生成
getSqlSession().getMapper(UserMapper.class).getUser(); 这一步也是通过代理实现
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | 1. ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 类加载器2. Class[] classes = {UserService.class} 目标对象的接口数组
 3. new InvocationHandleer() 附加操作 额外功能
 proxy = (UserServic)Proxy.newProxyInstance(classLoader, classes, new InvocationHandleer(){
 
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 
 log(method.getName());
 
 Object result = method.invoke(new UserServiceImpl(), args);
 return result;
 }
 public void log(String msg){
 System.out.println("执行了"+msg);
 }
 });   生成动态对象
 
 porxy.save();  直接调用
 
 | 
封装成通用的
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 
 | public class ProxyInvocationHandler implements InvocationHandler {
 
 private Object target;
 
 public void setTarget(Object target) {
 this.target = target;
 }
 
 
 public Object getProxy(){
 
 return Proxy.newProxyInstance(this.getClass().getClassLoader(),
 target.getClass().getInterfaces(),this);
 }
 
 
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 
 log(method.getName());
 Object result = method.invoke(target, args);
 return result;
 }
 
 public void log(String msg){
 System.out.println("执行了"+msg);
 }
 }
 
 ---------
 
 ServiceImpl service = new ServiceImpl();
 
 ProxyInvocationHandler phi = new ProxyInvocationHandler();
 
 phi.setTarget(service);
 
 Service proxy = (Service) phi.getProxy();
 
 proxy.add();
 
 | 
6.   AOP
Aspect Oriented Programing    核心就是动态代理
附加操作:如日志打印,每个controller都加的话代码冗余
通过动态代理完成附加操作(通知、Advice)。开发通知类,配置切入点
通知(Advice):前置通知、后置通知、环绕通知、异常通知
切入点(pointcut):指定通知应用在哪里。一般用于业务层
切面(Aspect):通知(Advice)+ 切入点(pointcut)
- 导入依赖 
- 开发通知   继承接口 MethodIntercept MethodBeforeAdvice  .. | 12
 3
 4
 5
 
 | public class Log implements MethodBeforeAdvice {public void before(Method method, Object[] objects, Object o) throws Throwable {
 System.out.println("执行了"+method.getName()+"方法");
 }
 }
 
 |  
 
- 配置切面 .xml - 被切的类都会创建代理对象,之后.getBean(“UserserviceImpl”)返回的是proxy,和5中动态代理一样,但每个被切的类不用单独创建 
环绕通知
MethodInterceptor
计算运行时间 、处理异常

切入点表达式


 
7.  复杂对象
- 简单对象:可以直接new的对象,因此可以直接通过< bean >交给spring
- 复杂对象:不能直接new,接口Connction、抽象类Calendar
Implements FactoryBean<类名>

8.整合mybatis
spring:项目管理
mybatis:持久层CRUD。把mybatis中的对象创建交给spring
mybatis写法:  .xml包含 数据源 以及 mapper注册 。 sqlSessionFactory =》sqlSession =》 usermapper
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 
 | 1.配置文件mybatis.xml 包含数据源信息(数据库账号密码等)2.从配置文件.xml得到SqlSessionFactory,再openSession生成SqlSession执行sql语句 (封装成工具类)
 private static SqlSessionFactory sqlSessionFactory;
 static {
 String resource = "mybatis-config.xml";
 try {
 
 InputStream inputStream = Resources.getResourceAsStream(resource);
 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 
 
 public static SqlSession getSqlSession(){
 return sqlSessionFactory.openSession();
 }
 
 3.编写Dao接口,接口实现类(.xml)
 
 4.注册Mapper.xml
 <mappers>
 <mapper resource="com/kuang/dao/userMapper.xml"/>
 </mappers>
 
 5.测试,调用工具类得到SqlSession,再调用getMapper,该mapper执行函数完成查询
 
 SqlSession sqlSession = MybatisUtils.getSqlSession();
 
 UserMapper mapper = sqlSession.getMapper(UserMapper.class);
 List<User> userList = mapper.getUserList();
 
 | 
8.1拿到sqlSessionFactory
SqlSessionFactoryBuilder 读配置文件,构建Factory
sqlSessionFactory 核心对象, 因此整合的核心就是接管这个!!!
sqlSession
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 
 | sqlSessionFactory 是接口,因此利用第七节的方法完成配置,并把xml文件位置通过依赖注入到bean中
 spring将这个类封装了,叫做SqlSessionFactoryBean
 注入.xml,细粒度化,把dataSource分开了,同时配置mapperLocations;mybatis.xml中配置日志等其他对象(可以不要)
 
 <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
 <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
 <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8"></property>
 <property name="username" value="root"></property>
 <property name="password" value="123456"></property>
 </bean>
 
 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
 
 <property name="dataSource" ref="dataSource"></property>
 
 <property name="mapperLocations" value="classpath:com/kuang/mapper/*.xml"></property>
 
 <property name="configLocation" value="classpath:mybatis-config.xml"/> (可以不要)
 </bean>
 
 到这一步拿出sqlSessionFactory,就可以取出sqlSession.getmapper操作数据库
 但我们的核心是在Dao部分,所以不想每次拿Dao时都先拿出sqlSessionFactory,想直接拿出Dao
 
 | 
8.2整和Dao
| 12
 
 | factory中指向mapper文件<property name="mapperLocations" value="classpath:com/kuang/mapper/*.xml"></property>
 
 | 
进一步封装,就可以直接getBean(UserDao)
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | sqlSessionFactory和userDao绑定,就可以直接getMapper,等价 @Mapper,每一个都要写。@Repository没有用<bean id="userDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
 <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
 <property name="mapperInterface" value="com.kuang.mapper.UserDao"></property>
 </bean>
 
 这里每一个Dao都要配置,直接只写一个mapperscan可以解决  等价 @MapperScan
 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
 <property name="basePackage" value="org.mybatis.spring.sample.mapper" />
 <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
 </bean>
 
 | 
或者将sqlsession作为一个成员放到UserDaoImpl中,间接调用,狂神的课程
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | public class UserMapperImpl implements UserMapper{private SqlSessionTemplate sqlSession;
 
 public void setSqlSession(SqlSessionTemplate sqlSession) {
 this.sqlSession = sqlSession;
 }
 
 public List<User> getUser() {
 UserMapper mapper = sqlSession.getMapper(UserMapper.class);
 return mapper.getUser();
 }
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
 <constructor-arg index="0" ref="sqlSessionFactory"/>
 </bean>
 
 
 <bean id="userMapper" class="com.kuang.mapper.UserMapperImpl">
 <property name="sqlSession" ref="sqlSession"></property>
 </bean>
 
 | 
9.Service事务
| 1
 | 用DataSourceTransactionManager实现事务,自己写try-catch  ->  写环绕通知  ->  用spring的环绕通知(细粒度)
 | 
service直接注入Dao即可,但需要处理事务
9.1.编程式
每个impl中注入事务管理对象实现
JDBC中
| 12
 3
 
 | connection.setAutoCommit(false);connection.commit();
 connection.rollback();
 
 | 
datasouce中可以取出connection,但是service中的connection和dao中的可能不是同一个
 
DataSourceTransactionManager:全局事务管理,使得service和Dao连接对象相同,控制数据源的线程安全问题
| 12
 3
 4
 
 | <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
 <property name="dataSource" ref="dataSource"></property>
 </bean>
 
 | 
serviceImpl中,添加transactionManager, .commit()   .rollback()。每一个serviceImpl都要写,用AOP解决冗余

9.2 声明式事务
aop实现事务处理
自己写:环绕通知,大家都一样的,所以spring封装了

封装后:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | <tx:advice id="txAdvice" transaction-manager="transactionManager">
 <tx:attributes>
 
 <tx:method name="add"/>
 <tx:method name="delete"/>
 <tx:method name="update*"/> 方法名需要对应上
 </tx:attributes>
 </tx:advice>
 
 
 <aop:config>
 <aop:pointcut id="tranPointCut" expression="execution(* com.kuang.mapper.*.*(..))"></aop:pointcut>
 <aop:advisor advice-ref="txAdvice" pointcut-ref="tranPointCut"></aop:advisor>
 </aop:config>
 
 | 
9.3事务传播
业务层中调用别的业务,可以把事务传播过去。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | OrderService.save(){userService.update();
 }
 <tx:method name="add" />
 propagation=""
 REQUIRED:外层没有则开启,有则融入             增删改  默认
 SUPPORTS:外层没有不开,有则融入;实现事务传播  查询
 REQUIRE_NEW: 自己开一个新的 隔开              银行日志,总是要个新的
 NOT_SUPPORTED: 不用事务
 isolation=""
 read-only
 time-out: 事务超时 -1永不超时 秒
 
 | 
行锁为一条数据,在同一事务中多次查询,不会受到别人update印象
表锁为表的数据,多一条少一条不受印象

10.日志
log4j
ERROR WARN INFO DEBUG
配置文件在resource根目录下
| 1
 | log4j.logger.com.baizhi.dao=DEBUG 展示sql
 | 
11.注解
装配
service太多了,每次都要添加
前置条件:开启注解扫描
| 12
 
 | <context:component-scan base-package="com.kuang"/>
 
 | 
@component(value = “指定id”),装配到Spring中,等价与< bean>, 唯一标识为类名小写
- Dao		  **@Repository (只是告诉spring要加这个bean,和mybatis无关)   ** @Mapper 和 @MapperScan结合使用为了结合spring和mybatis。如果不加@Repository可能爆红 但能正常运行
- Service     @Service
- controller  @ Controller
@Scope(value=”singleton\prototype”)  单例多例
注入
对象注入 属性或者set方法上。在属性上用时可以不用添加set方法,底层会自动提供set方法
	@Autowired  默认类型
	 @Qualifier(value = “cat1”)  指定名称
JavaEE
	@Resource  默认名字,找不到再类型
基本类型注入
	@Value(“XX”)         @Value(“${spring.datasource.username}”)
事务
@transactional(propagation = , )  添加事务,加载类或者单个方法    serviceimpl上加
不需要事务通知对象以及添加切面,但还是添加开启注解事务
| 1
 | <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven > 
 | 
 
Dao还是扫描进行装配的
P21整合SM
SpringMVC
MVC中的C层,控制器框架。代替struts2
0.Struct2
1.C层:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | public class ProductAction extends ActionSupport {private List<Product> productList;
 
 public String list() {
 
 productList = ProductService.getProductList();
 return SUCCESS;
 }
 
 public List<Product> getProductList() {
 return productList;
 }
 }
 
 
 | 
2.路由:封装servlet,Struts2的前端控制器DispatcherServlet接收并分发到对应的Action处理。
定义名为productList的Action,并将其关联到ProductAction类中的list()方法。当请求到达/productList时,Struts2会调用list()方法并将结果返回到productList.jsp页面中。
| 12
 3
 4
 5
 6
 7
 
 | <struts><package name="product" extends="struts-default">
 <action name="productList" class="com.example.ProductAction" method="list">
 <result name="success">/WEB-INF/views/productList.jsp</result>
 </action>
 </package>
 </struts>
 
 | 
3.V层:配置Struts2的视图
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 
 | <%@ taglib prefix="s" uri="/struts-tags" %><html>
 <head>
 <title>Product List</title>
 </head>
 <body>
 <table>
 <thead>
 <tr>
 <th>ID</th>
 <th>Name</th>
 <th>Price</th>
 <th>Description</th>
 </tr>
 </thead>
 <tbody>
 <s:iterator value="productList">
 <tr>
 <td><s:property value="id"/></td>
 <td><s:property value="name"/></td>
 <td><s:property value="price"/></td>
 <td><s:property value="description"/></td>
 </tr>
 </s:iterator>
 </tbody>
 </table>
 </body>
 </html>
 
 
 | 
1.基本思想
在servlet基本思想中,编写一个控制器,就要去web.xml中去注册,在SpringMVC中,使用dispatchservlet拦截所有
| 12
 3
 4
 5
 6
 7
 8
 
 | <servlet><servlet-name>loginout</servlet-name>
 <servlet-class>com.xiao.servlet.user.LogoutServlet</servlet-class>
 </servlet>
 <servlet-mapping>
 <servlet-name>loginout</servlet-name>
 <url-pattern>/jsp/logout.do</url-pattern>
 </servlet-mapping>
 
 | 
配置web.xml(拦截全部的请求)   配置springmvc.xml      编写controller(component-scan)

- web.xml | 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | <servlet>
 <servlet-name>springmvc</servlet-name>
 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
 
 <init-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>classpath:springmvc-servlet.xml</param-value>
 </init-param>
 </servlet>
 
 
 <servlet-mapping>
 <servlet-name>springmvc</servlet-name>
 <url-pattern>/</url-pattern>
 </servlet-mapping>
 
 |  
 
- springmvc.xml | 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | <?xml version="1.0" encoding="UTF-8"?><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 class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
 
 <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
 
 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
 id="InternalResourceViewResolver">
 
 <property name="prefix" value="/WEB-INF/jsp/"/>
 
 <property name="suffix" value=".jsp"/>
 </bean>
 
 </beans>
 
 |  
 
| 12
 
 | <mvc:annotation-driven />  包含映射器、适配器  实验发现是必须要
 
 |  
 
- 编写controller | 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | 手动配置,这里的id就是访问的路径<bean id="/helloserv" class="com.kuang.controller.Helloservlet"></bean>
 
 或者 不可以同时配置
 
 <!-- 注解扫描 -->
 <context:component-scan base-package="com.kuang.controller"/>
 
 @Controller
 public class HelloServlet {
 
 @RequestMapping("/helloserv")
 public String hello(Model model){
 model.addAttribute("msg","hello annotation");
 return "hello";
 }
 }
 
 |  
 
- 在 Controller 中,根据业务逻辑查询出需要显示的动态数据,并将其封装成一个 Model 对象。
- 将 Model 对象作为参数传递给模板引擎(根据返回值定位页面),通过 Thymeleaf 的表达式语言 ${} 将动态数据注入到 HTML 模板中。
- Thymeleaf 模板引擎会根据 HTML 模板中定义的逻辑和数据,生成渲染后的 HTML 页面,并将其返回给客户端浏览器。
- 客户端浏览器接收到 HTML 页面后,根据 HTML 标签和 CSS 样式渲染页面,并显示给用户。
想访问一个商品列表页面:
- controller定义toList接口,
- 加载数据到model里,return “toList”跳转到toList.html,thymeleaf会自动渲染数据进入页面对应的${}
2.跳转
servlet
- forward 请求转发 地址栏不变,获得商品列表后转发到商品界面
- redirect 重定向
controller -> 页面       
- 默认返回就是forward
- 重定向return “redirect:/index.jsp”  不经过视图解析器
controller -> controller 
- return “forward:/path”
- return “redirect:/path”
3.参数接受
vo:专门用来传值的对象
struts2:成员变量接收参数 多例
springmvc:
@RequestBody 反序列化 @ResponseBody 序列化成json 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | 局部变量,无线程安全问题,单例
 
 @RequestMapping("/test2/{pageNo}“)
 @PathVariable int pageNo 将URL中的占位符参数绑定到控制器处理方法的入参
 
 @RequestParam String name  	Url Form表
 User user  url中自动对应
 
 @RequestBody User user  	Body中raw格式下的json参数
 
 | 
前端可以混用,一个在params,一个在data
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | @RequestParam String resourceId,@RequestParam String examId,
 @RequestBody List<UpdateExamAnswer> examAnswerList,
 @RequestParam(value = "writeType", defaultValue = "0") int writeType
 
 return request({
 url: BASE_URL + '/submit_all_save',
 method: 'post',
 params: {
 resourceId,
 examId,
 writeType
 },
 data: questionRes
 })
 
 | 
此外,以上默认post为application/json格式发送接受数据
- application/x-www-form-urlencoded前端URLSearchParams或Qs.Stringify(data)      后端@RequestParam或不加
| 12
 3
 4
 5
 6
 7
 8
 
 | 数据格式:loginName=lst&password=1
 
 百分号编码:
 丁 十六进制下是0xE4B881占3字节
 转成字符串‘E4B881’,占六字节
 每两个字节前加上百分号前缀,得到字符串“%E4%B8%81”,占九个字节(十六进制下是0x244534254238253831)
 把这九个字节拼接到数据包里,这样就可以传输“非ascii字符的  utf8编码的 十六进制表示的 字符串的 百分号形式”
 
 | 
3.multipart/form-data  前端FormData格式,后端@RequestParam或不加
4.返回参数:
request(单次请求)  session(浏览器) application(全体用户共享)
| 12
 3
 4
 5
 6
 7
 
 | forward跳转Model model 对request的封装,作用一样
 model.addAttribute("msg","hello annotation");
 取出:${requestScope.msg}
 redirect
 1.地址栏拼接
 2.session  req.getSession.setAttribute
 
 | 
5.拦截器
javaweb:filter过滤器,可以拦截一切资源。springmvc只能拦截controller
编写拦截器类,再注册:注入bean,定义拦截的地方。(或者定义和拦截写在一起)
这里继承HandlerInterceptor,有处理前,(controller)处理后,清理后
AOP
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 
 | public class JWTInterceptor implements HandlerInterceptor {public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
 
 if ("OPTIONS".equals(request.getMethod())) {
 return true;
 }
 
 String token = request.getHeader("token");
 HashMap<String, Object> map = new HashMap<>();
 if(token == null){
 map.put("msg","未携带token");
 }else{
 try{
 JWTUtils.verity(token);
 
 return true;
 }catch (SignatureVerificationException e){
 e.printStackTrace();
 map.put("msg","无效签名");
 }catch (TokenExpiredException e){
 e.printStackTrace();
 map.put("msg","token过期");
 }catch (AlgorithmMismatchException e){
 e.printStackTrace();
 map.put("msg","token算法不一致");
 }catch (Exception e){
 e.printStackTrace();
 map.put("msg","token无效");
 }
 }
 
 map.put("code",500);
 map.put("data",null);
 String json = new ObjectMapper().writeValueAsString(map);
 response.setContentType("application/json;charset=UTF-8");
 response.getWriter().println(json);
 return false;
 }
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 
 | <mvc:interceptors>
 
 <mvc:interceptor>
 <mvc:mapping path="/**"/>
 <bean class="com.kuang.config.JWTInterceptor"></bean>  或者分开 <ref bean = "beanname">
 </mvc:interceptor >
 </mvc:interceptors>
 
 | 
6.异常处理
编写异常处理类,注册bean就行。可以根据不同的异常if判断处理不同逻辑 

SSM
这里7.a scan可以只扫描service下的,因为mapper和controller都扫描了;mapper可以不使用注解(mapperscanconfig是和spring整合的;等价在springboot中使用了@Mapper或@MapperScan)


| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 
 | 	<context:component-scan base-package="com.kuang.service"/>
 
 
 
 
 
 
 
 
 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
 <property name="dataSource" ref="dataSource"></property>
 </bean>
 
 
 <tx:annotation-driven transaction-manager="transactionManager"/>
 
 
 
 <context:property-placeholder
 location="classpath:database.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="30"/>
 <property name="minPoolSize" value="10"/>
 
 <property name="autoCommitOnClose" value="false"/>
 
 <property name="checkoutTimeout" value="10000"/>
 
 <property name="acquireRetryAttempts" value="2"/>
 </bean>
 
 
 <bean id="sqlSessionFactory"
 class="org.mybatis.spring.SqlSessionFactoryBean">
 
 <property name="dataSource" ref="dataSource"/>
 
 <property name="configLocation" value="classpath:mybatis-config.xml"/>
 </bean>
 
 
 
 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
 
 <property name="sqlSessionFactoryBeanName"
 value="sqlSessionFactory"/>
 
 <property name="basePackage" value="com.kuang.dao"/>
 </bean>
 
 | 
1.ab 让mvc在服务器启动时创建工厂(提供service Dao)。
实际项目中,可以把所有的文件整合到一起applicationContext,在servlet中配置



C:\Users\13000\Desktop\study\vue-spring\2.vue-spring\7.springmvc\0代码———————————-\ssmbuild
spring.xml
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 
 | 
 <context:property-placeholder
 location="classpath:database.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="30"/>
 <property name="minPoolSize" value="10"/>
 
 <property name="autoCommitOnClose" value="false"/>
 
 <property name="checkoutTimeout" value="10000"/>
 
 <property name="acquireRetryAttempts" value="2"/>
 </bean>
 
 
 <bean id="sqlSessionFactory"
 class="org.mybatis.spring.SqlSessionFactoryBean">
 
 <property name="dataSource" ref="dataSource"/>
 
 <property name="configLocation" value="classpath:mybatis-config.xml"/>
 </bean>
 
 
 
 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
 
 <property name="sqlSessionFactoryBeanName"
 value="sqlSessionFactory"/>
 
 <property name="basePackage" value="com.kuang.dao"/>
 </bean>
 
 
 
 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
 <property name="dataSource" ref="dataSource"></property>
 </bean>
 <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven >
 
 
 <context:component-scan base-package="com.kuang.service"/>
 
 
 
 
 
 | 
springmvc.xml
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 
 | <context:component-scan base-package="com.kuang.controller"/>
 
 <mvc:default-servlet-handler/>
 
 <mvc:annotation-driven/>
 
 
 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
 id="InternalResourceViewResolver">
 
 <property name="prefix" value="/WEB-INF/jsp/"/>
 
 <property name="suffix" value=".jsp"/>
 </bean>
 
 
 web.xml
 <servlet>
 <servlet-name>dispatchservlet</servlet-name>
 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
 <init-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>classpath:applicationContext.xml</param-value>
 </init-param>
 <load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
 <servlet-name>dispatchservlet</servlet-name>
 <url-pattern>/</url-pattern>
 </servlet-mapping>
 
 |