SSM
Spring IOC 实现原理 - 简书 (jianshu.com)
注意javajdk版本的区别 必须相等
当scope的取值为singleton时
Bean的实例化对象个数:1个
Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例
Bean的声明周期:
当scope的取值为prototype时
Bean的实例化对象个数:多个
Bean的实例化时机:当调用getBean()方法时实例化Bean
Bean的声明周期:
有两种注入Bean的方式
set
构造器方法的注入 —不用写set方法
注入数据的三种数据属性
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
<property name="username" value="zhangsan"/>
<property name="age" value="18"/>
bean>
引用数据类型
集合数据类型
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
<property name="strList">
<list>
<value>aaavalue>
<value>bbbvalue>
<value>cccvalue>
list>
property>
<property name="userMap">
<map>
<entry key="u1" value-ref="user1">entry>
<entry key="u2" value-ref="user2">entry>
map>
property>
<property name="properties">
<props>
<prop key="p1">ppp1prop>
<prop key="p2">ppp2prop>
<prop key="p3">ppp3prop>
props>
property>
bean>
<bean id="user1" class="com.itheima.domain.User">
<property name="name" value="tom"/>
<property name="addr" value="beijing"/>
bean>
<bean id="user2" class="com.itheima.domain.User">
<property name="name" value="lucy"/>
<property name="addr" value="tianjin"/>
bean>
<import resource="applicationContext-user.xml"/>
标签:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D3VyEqPm-1652271393849)(C:\Users\29769\AppData\Roaming\Typora\typora-user-images\image-20220410173610216.png)]
常见的数据源(连接池):DBCP C3P0 BoneCP Druid等
使用properties来配置数据库的基本信息
基本的抽取的配置文件 方便解耦
在resources资源包下创建jdbc.properties—里面写的是数据库的配置
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/game
jdbc.username=root
jdbc.password=root
bean标签里的Class是创建数据源对象的方法地址
在方法里有两种getbean的方式
首先读取Spring的xml配置文件:ApplicationCaotext app = new ClassPathXmlApplicationContext("applicationCaotext.xml ")
在Spring的bean标签里加载其他properties的配置文件内容
获取properties的value用spring的表达式${key(指的是properties里的key)}
Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率
Spring原始注解主要是代替****的配置
userService需要用到userDao里的save方法 原本是userDao放到了Spring容器里,但现在在Service里调用到userDao里的save方法
需要把userService也放到容器里,将userDao注入到service里更加简便
@Componment(“userDao”)放在方法的头部 来表示此方法放入spring容器里
引号里的字符串相当于xml文件里Bean标签的id spring根据包去扫描对应的id来寻找对应的注入
@Autowired
@Qualifier(userDao)
相当于properties (set的方法名)和ref(“注谁?”)
这是告诉spring Dao 注入到Service
在使用xml配置的方法的时候必须要写对象的set的方法
而在使用注解的方式则可以省略写set方法 因为spring会调用反射技术为其赋值 也可以省略**@Qualifier(userDao)的注解 因为@Autowired是按照数据类型**从Spring容器中进行匹配,找到对应的bean类型放入,但是只能如果有多个相同类型的bean则不能匹配
@Qualifier(userDao)是按照id的值从容器中进行匹配的,但是必须结合**@Autowired**一起使用
按照数据类型注入:@Autowired
按照id值注入:@Autowired+@Qualifier(userDao)
@Resource(“userDao”) = @Autowired+@Qualifier(“userDao”) 按照id注入
@Value(”aaaa“)
private String driver --------->driver = aaaa
SpringConfiguration Spring的核心配置类
DataSourceConfiguration是加载数据源的配置类------>存放数据库账号密码等数据
但是Spring的核心配置类只能有一个 所以需要在SpringConfiguration 引用外部类
使用@import(需要引用的外部类的名字.calss)标签来引用
如果需要加载多个则@import({需要引用的外部类的名字.calss,XXX,XXXX})
JUnit - 概述_w3cschool
什么是 JUnit?
JUnit 是一个 Java 编程语言的单元测试框架。JUnit 在测试驱动的开发方面有很重要的发展,是起源于 JUnit 的一个统称为 xUnit 的单元测试框架之一。
JUnit 促进了“先测试后编码”的理念,强调建立测试数据的一段代码,可以先测试,然后再应用。这个方法就好比“测试一点,编码一点,测试一点,编码一点……”,增加了程序员的产量和程序的稳定性,可以减少程序员的压力和花费在排错上的时间。
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) app.getBean("userDao");
获取spring容器上的对象就要getbean ,然而每次都要写
所以:
让SpringJunit负责创建Spring容器,但是需要将配置文件的名称告诉它
将需要进行测试Bean直接在测试类中进行注入
导入Spring集成Junit的坐标
使用@Runwith注解替换原来的运行期
使用@ContextConfiguration指定配置文件和配置类
使用@Autowired注入需要进行测试的对象
创建测试方法进行测试
全注解集成指定Spring的核心配置类
首先创建了web包下的UserServlet,在类里读取Spring的配置文件 获取spring容器的bean对象 userService来调用Dao层的UserDaoImpl的save方法
在web.xml的文件下添加配置源
<servlet>
<servlet-name>UserServletservlet-name>
<servlet-class>com.itheima.web.UserServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>UserServletservlet-name>
<url-pattern>/userServleturl-pattern>
servlet-mapping>
应用上下文对象是通过new ClassPathXmlApplicationContext(spring配置文件)方式获取的,但是每次从容器在获得Bean时都要编写new ClassPathXmlApplicationContext(spring配置文件),这样的弊端是配置文件加载多次,应用上下文对象多次创建。所以我们需要只要应用上下文对象spring容器创建一次,web的组件谁想用谁去拿就行了
---------用监听器来创建
在Web项目中,可以使用ServletContextListener监听Web应用的启动,我们可以在Web应用启动时,就加 我Spring的配置文件,创建建应用上下文对象ApplicationContext, 在将其存储到最大的域sqsvletContext 中,这样就可以在任意位置从域中获得应用上下文ApplicationContext对象了。
ContextLoaderListener类
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext servletContext = servletContextEvent.getServletContext();
//读取web.xml中的全局参数
String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");
//获取spring上下文对象
ApplicationContext app = new ClassPathXmlApplicationContext(contextConfigLocation);
//将spring上下文对象存储到ServletContext域中
//上下文对象存入到ServletContext域中 名字是耦合死的 在运用的时候需要解耦方便写
servletContext.setAttribute("app",app);
System.out.println("spring容器创建完毕------init.......");
}
需要在web.xml里配置 让服务器能够识别
<!--配置监听器-->
<listener>
<listener-class>com.itheima.listener.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>com.itheima.web.UserServlet</servlet-class>
</servlet>
这里获得上下文对象名字是写死的不方便读取,需要进行解耦
ApplicationContext app = (ApplicationContext) servletContext.getAttribute("app");
创建WebApplicationContextUtils类来返回上下文对象的名字
public class WebApplicationContextUtils {
/**
* 解耦 上下文对象 名字
* @param servletContext
* @return
*/
public static ApplicationContext getWebApplicationContext(ServletContext servletContext){
return (ApplicationContext)servletContext.getAttribute("app");
}
}
在读取上下文对象的时候进行解耦了
//解除固定的app的名字用工具类来获取 解耦
// ApplicationContext app = (ApplicationContext) servletContext.getAttribute("app");
ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);
UserService userService = app.getBean(UserService.)
上面的分析不用手动实现,Spring提供了一个监听器ContextLoaderListener就是对上述功能的封装,该监 听器内部加载Spring配置文件,创建应用上下文对象,并存储到Servletcontextt中,提供了一个客户端工 具WebApplicationContextUtils供使用者获得应用上下文对象
如何使用
SpringMVC是一种基于Java 的实现 MVC 设计模型的请求驱动类型的轻量级 web 框架属于 SpringFrameWork的后续产品,已经融合在 Spring Web Fiow中
SpringMVC已经成为目前最主流的MVC框架之一,并且随者Spring3.0的发布,全面超越Struts2,成为最优秀的MVC框架。
它通过一套注解,让一个简单的Java 类成为处理请求的控制器,而无须实现任何接口。同时 它还支持 RESTful 编程风格的请求。
从代码上分析的流程图
逻辑上的流程图
@RequestMapping:用于建立请求URL和处理请求方法之间的对应关系
属性:
列如:
@RequestMapping(value"/quick",method=RequestMethod.GET.params={“username”})
请求映射注解:@RequestMapping
视图解析器配置: REDIRECT_URL_PREFIX = “redirect.” FORWARD URL PREFIX = “forward:”
前缀:prefix=“”
后缀:suffix=“”
@RequestMapping("/quick5")
public String save4(HttpServletRequest request){
/*
Model:模型 作用封装数据
*/
request.setAttribute("username","MBM");
return "/success.jsp";
}
@RequestMapping("/quick4")
public String save4(Model model){
/*
Model:模型 作用封装数据
*/
model.addAttribute("username","MsM");
return "/success.jsp";
}
/**
* 传参的modelAndView spring发现需要为它传递参数
* 从而在spring容器里拿出modelAndView 传递过来
* @param modelAndView
* @return
*/
@RequestMapping("/quick3")
public ModelAndView save3(ModelAndView modelAndView){
/*
Model:模型 作用封装数据
View: 视图 作用参数数据
*/
//添加模型数据
modelAndView.addObject("username","MVM");
//设置视图名称
modelAndView.setViewName("/success.jsp");
return modelAndView;
}
@RequestMapping("/quick2")
public ModelAndView save2(){
/*
Model:模型 作用封装数据
View: 视图 作用参数数据
*/
ModelAndView modelAndView = new ModelAndView();
//添加模型数据
modelAndView.addObject("username","itcast");
//设置视图名称
modelAndView.setViewName("/success.jsp");
return modelAndView;
}
//请求地址 http://localhost:8080/user/quick
@RequestMapping("/quick")
public String save(){
System.out.println("controller save running....");
//转发默认省略了forward
// forward:/success.jsp
//重定向默认省略了redirect
// redirect:/success.jsp
return "/success.jsp";
}
1.通过传入参数一样由Spring容器给方法传入HttpServletRespone对象来在页面上回写字符串、
@RequestMapping("/quick6")
public void save6(HttpServletResponse response) throws IOException {
response.getWriter().write("hello,heima");
}
2.将需要回写的字符串直接返回,但此时需要通过@ResponseBody注解告知SpringMVC框架,方法返回的字符串不是跳转是直接在http响应体中返回
@RequestMapping("/quick7")
@ResponseBody
public String save7() throws IOException {
return "hello,heima·";
}
原本利用JSON转换工具转换成JSON格式字符串对象再返回
@RequestMapping("/quick9")
@ResponseBody //告知SpringMVC框架该方法不进行视图跳转 直接进行数据响应
public String save9() throws IOException {
User user = new User();
user.setName("lisi");
user.setAge(30);
//使用JSON的转换工具将对象转换成JSON格式的字符串返回
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(user);
return json;
}
现在有Spring-mvc的配置更加方便能传递
首先在Spring-mvc的xml文件下配置
<!--配置处理器映射器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</list>
</property>
</bean>
可以使用mvc注解驱动更加方便的注入
而调用的时候直接返回User类型的对象即可 在页面上返回对象或集合
@RequestMapping("/quick10")
@ResponseBody //告知SpringMVC框架该方法不进行视图跳转 直接进行数据响应
//期望SpringMVC将user转换成JSON格式的字符串格式返回
public User save10() throws IOException {
User user = new User();
user.setName("lisi");
user.setAddr("nmmdw");
user.setAge(30);
return user;
}
user/quick11?username=zhangsan&age=11
控制台直接打印 zhangsan 11
@RequestMapping("/quick11")
@ResponseBody //告知SpringMVC框架该方法不进行视图跳转 直接进行数据响应
public void save11(String username,int age) throws IOException {
System.out.println(username);
System.out.println(age);
}
Controller中的业务方法的POJO参数的属性名与请求参数的name一致,参数会自动映射匹配。
封装一个实体对象就是在一次数据返回的时候SpringMVC会自动的去匹配和请求参数属性一致的属性进行写入,最后封装成一个对象属性
user/quick11?username=zhangsan&age=11&addr=beijing
控制台会打印对应的实体类属性
@RequestMapping("/quick12")
@ResponseBody //告知SpringMVC框架该方法不进行视图跳转 直接进行数据响应
public void save12(User user) throws IOException {
System.out.println(user);
}
Controller中的业务方法的POJO参数的属性名与请求参数的name一致,参数会自动映射匹配。
/user/quick13?str=aaaa&str=bbbb&str=cccc
控制台会打印数组数据
@RequestMapping("/quick13")
@ResponseBody //告知SpringMVC框架该方法不进行视图跳转 直接进行数据响应
public void save13(String []str) throws IOException {
System.out.println(Arrays.asList(str));
}
封装成一个对象集合,首先创建一个对象集合类,来get和set集合对象,这种是通过页面的form表单来获取相应属性
public class VO {
private List<User> userList;
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this.userList = userList;
}
@Override
public String toString() {
return "VO{" +
"userList=" + userList +
'}';
}
}
通过表单上来获取对象的属性,从而写入到对象集合中去
首先得访问对应的页面将数据填入到表单中提交事务后
<form action="${pageContext.request.contextPath}/user/quick14" method="post">
<%--表明第一个User对象的username age addr--%>
<input type="text" name="userList[0].username"><br/>
<input type="text" name="userList[0].age"><br/>
<input type="text" name="userList[0].addr"><br/>
<input type="text" name="userList[1].username"><br/>
<input type="text" name="userList[1].age"><br/>
<input type="text" name="userList[1].addr"><br/>
<input type="submit" value="提交">
form>
在控制台打印对象集合
@RequestMapping("/quick14")
@ResponseBody //告知SpringMVC框架该方法不进行视图跳转 直接进行数据响应
public void save14(VO vo) throws IOException {
System.out.println(vo);
}
当使用Ajax提交时,可以指定contentType为json形式,那么在方法参数位置使用@RequestBody可以直接接收集合数据无需使用POJO进行包装
在获取资源jquery-3.3.1.js的时候需要静态读取----在Spring-mvc.xml里添加
开发静态资源的访问
才能使用静态资源
<head>
<title>Titletitle>
<script src="${pageContext.request.contextPath}/js/jquery-3.3.1.js">script>
<script>
var userList = new Array();
userList.push({username:"zhangsan",age:18,addr:"beijing"});
userList.push({username:"zhanger",age:17,addr:"sandong"});
$.ajax({
type:"POST",
url:"${pageContext.request.contextPath}/user/quick15",
data:JSON.stringify(userList),
contentType:"application/json;charset=utf-8"
})
script>
head>
在使用ajax发送请求后,将对象数据封装在userList里一起传递到后端,这样就可以直接接收集合数据
@RequestBody将请求体的数据直接封装到参数位置的参数里
结果会在控制台打印对象集合数据
@RequestMapping("/quick15")
@ResponseBody //告知SpringMVC框架该方法不进行视图跳转 直接进行数据响应
public void save15(@RequestBody List<User> userList) throws IOException {
System.out.println(userList);
}
静态资源的访问
mapping:对应访问服务端的地址 找谁
location:具体资源所在的目录 那个目录下的资源
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:default-servlet-handler/>
请求数据乱码问题
可以设置一个过滤器来进行编码的过滤
<filter>
<filter-name>CharacterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
参数绑定注解@RequestParam
当请求的参数名称与Controllerd的业务方法参数不一致时,就需要通过@RequestParam注解显示的绑定
user/quick16?name=zhangsan 绑定username 一样可以在控制台打印数据
@RequestMapping("/quick16")
@ResponseBody //告知SpringMVC框架该方法不进行视图跳转 直接进行数据响应
public void save16(@RequestParam("name") String username) throws IOException {
System.out.println(username);
}
Restful是一种软件架构风格,设计风格,而不是标准,只是提供了一组设计原则和约束条件。主要用于客户端和服务器交互类的软件,基于这个风格设计的软件可以更加简洁,更有层次,更易于实现缓存机制等。
Restful风格的请求是使用“url+请求方式”表示一次请求目的的,HTTP协议里面四个表示操作方式的动词如下:
列如:
//访问地址:localhost:8080/user/quick17/zhangsan
上述url地址/user/1中的1就是要获得的请求参数, 在SpringMVC中可以使用占位符进行参数绑定。地址/user/1可以写成 user/ id)。占位符(id}对应的就是1的值。在业务方法中我们可以使用**@PathVariable注解进行占位符的匹配获取工作**。
//访问地址:localhost:8080/user/quick17/zhangsan
@RequestMapping("/quick17/{username}")
@ResponseBody //告知SpringMVC框架该方法不进行视图跳转 直接进行数据响应
public void save17(@PathVariable("username") String username) throws IOException {
System.out.println(username);
//打印zhangsan
}
自定义类型转换器的开发步骤:
1.定义转换器类实现Converter接口
将时间yyyy-MM-dd类型转换成format类型,自己实现接口
public class DateConverter implements Converter<String,Date> {
public Date convert(String dataStr) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = format.parse(dataStr);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
2.在配置文件中声明转换器
这个配置相当于一个bean对象,声明一个bean丢到容器中,进行类的地址读入
<!--声明日期转换器 -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.itheima.converter.DateConverter"></bean>
</list>
</property>
</bean>
3.在中引用转换器
<mvc:annotation-driven conversion-service="conversionService"/>
SpringMVC支持使用原始ServletAPI对象作为控制器方法参数的注入,常用对象如下:
//获得servlet对应的API 使用参数注入的方法即可
@RequestMapping("/quick19")
@ResponseBody //告知SpringMVC框架该方法不进行视图跳转 直接进行数据响应
public void save19(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException {
System.out.println(request);
System.out.println(response);
System.out.println(session);
}
使用@@RequestHeader可以获得请求头信息,相当于web阶段学习的request.getHeader(name)
@RequestHeader的注解属性如下:
@RequestMapping("/quick20")
@ResponseBody //告知SpringMVC框架该方法不进行视图跳转 直接进行数据响应
public void save20(@RequestHeader(value = "User-Agent",required = false) String user_agent) throws IOException {
System.out.println(user_agent);
}
使用**@CookieValue**可以指定Cookie的值
@CookieValue注解属性如下:
@RequestMapping("/quick21")
@ResponseBody //告知SpringMVC框架该方法不进行视图跳转 直接进行数据响应
public void save21(@CookieValue(value = "JSESSIONID",required = false) String jsessionID) throws IOException {
System.out.println(jsessionID);
}
JSP页面
<form action="${pageContext.request.contextPath}/user/quick22"
method="post" enctype="multipart/form-data">
名称<input type="text" name="username"><br/>
文件<input type="file" name="upload"><br/>
<input type="submit" value="提交">
</form>
1.导入fileupload和io坐标
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.3version>
dependency>
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>1.3.1version>
dependency>
2.配置文件解析器
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxInMemorySize" value="5000000">property>
<property name="defaultEncoding" value="UYF-8">property>
bean>
3.编写文件上传代码
//MultipartFile 会上传的文件封装成一个对象 里面的参数
//(MultipartFile upload)必须和页面代码上类型为file的名字一致 文件
@RequestMapping("/quick22")
@ResponseBody //告知SpringMVC框架该方法不进行视图跳转 直接进行数据响应
public void save22(String username, MultipartFile upload) throws IOException {
System.out.println(username);
System.out.println(upload);
}
//将文件另存为本机新建文件下
upload.transferTo(new File("D:\\upload\\"+originalFilename));
当页面file类型的name是不同的时候 在后端代码接收的时候,有多少个文件,就写多少个MultipartFile且名字要对应
public void save22(String username, MultipartFile upload,MultipartFile upload1,MultipartFile upload2) throws IOException {
System.out.println(username);
String originalFilename = upload.getOriginalFilename();
upload.transferTo(new File("D:\\upload\\"+originalFilename));
String originalFilename1 = upload1.getOriginalFilename();
upload1.transferTo(new File("D:\\upload\\"+originalFilename1));
String originalFilename2 = upload2.getOriginalFilename();
upload2.transferTo(new File("D:\\upload\\"+originalFilename2));
}
当页面file类型的name相同的时候,传递到后台的文件是一个数组,需要用数组来接收 用循环来读出
//MultipartFile 会上传的文件封装成一个对象
@RequestMapping("/quick22")
@ResponseBody //告知SpringMVC框架该方法不进行视图跳转 直接进行数据响应
public void save22(String username, MultipartFile[] upload) throws IOException {
System.out.println(username);
for (int i = 0;i<upload.length;i++){
//获得文件名称
String originalFilename = upload[i].getOriginalFilename();
//将文件另存为本机新建文件下
upload[i].transferTo(new File("D:\\upload\\"+originalFilename));
}
}
它是spring框架中提供的一个对象,是对原始繁琐的JDBC API对象的简单封装。spring框架为我们提供了很多的操作模板类。
例如:操作关系型数据的JdbcTemplate和Hibernate Template,操作nosal数据库的Redis Template,操作消息队列的JmsTemplate等等
因为是数据库的操作需要在pom文件里导入mysql和c3p0的驱动jar包才能调用对应的类
我们可以将JdbcTemplate的创建权交给Spring,将数据源DateSource的创建权也交给Spring,在Spring容器内部将数据源DataSource注入到JdbcTemplate模板对象中
基于spring容器来抽取properties
<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}"/>
bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
bean>
注解形式注入的JdbcTemplate对象
@Autowired//从Spring容器里拿出JdbcTemplate自动注入
private JdbcTemplate jdbcTemplate;
xml文件方式读取的注入
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
JdbcTemplate jdbcTemplate = app.getBean(JdbcTemplate.class);
首先创建web层的控制器Controller来实现页面上个按钮的功能
(需要将其注入到spring容器里获得bean对象—这里使用的是注解形式:@Controller)
一个功能对应一个相应的方法返回对应的数据
@Controller//web层 注解方式产生bean存入spring容器 需要包扫描
public class RoleController
但是必须进行包扫描才能让spring来将其存入spring容器里
<context:component-scan base-package="com.itheima.controller"/>
ModelAndView的模型对象(—>显示roleService返回的对象数组)和跳转到新的相应界面
由此分析需要调用roleService里返回对应数据库表数据的操作
而roleService需要使用roleDao的findAll方法来查询表中所有的角色信息 因此需要将roleService和roleDao都注入到spring容器里
这里使用的是配置文件的形式注入,这里因为roleService调用了roleDao的方法最后实现是roleService来实现,所以需要将roleDao注入roleService里
<bean id="roleService" class="com.itheima.service.impl.RoleServiceImpl">
<property name="roleDao" ref="roleDao"/>
bean>
<bean id="roleDao" class="com.itheima.dao.impl.RoleDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
bean>
具体实现:
roleDao使用jdbcTemplate模板前需要创建jdbcTemplate模板类 setJdbcTemplate里的参数是spring容器自动填充(因为在spring的配置文件里配置了setJdbcTemplate对象)
//创建jdbc模板类
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate){
this.jdbcTemplate = jdbcTemplate;
}
roleDao使用jdbcTemplate模板操作数据库返回表对象信息
/**
* 返回查询sys_role表的所有成员信息
* @return roleList
*/
public List findAll() {
List roleList = jdbcTemplate.query("select * from sys_role", new BeanPropertyRowMapper(Role.class));
return roleList ;
}
roleService调用roleDao的findAll方法 由此返回数据给web端
public List<Role> list() {
List<Role> roleList = roleDao.findAll();
return roleList;
}
所以ModelAndView接收并设置模型对象 最后携带模型跳转到对应界面将数据显示
@RequestMapping("/list")
private ModelAndView list(){
ModelAndView modelAndView = new ModelAndView();
List<Role> roleList = roleService.list();
//设置模型对象
modelAndView.addObject("roleList",roleList);
//设置视图 向哪跳转
modelAndView.setViewName("role-list");
return modelAndView;
}
新建角色方法也差不多
在新建user关系中 一个user可能对应多个role 又因为是使用id值进行匹配的 id值是有数据库自动产生的 所以这里的id值需要去获取之后才能对角色表和人物关系表进行操作
获得数据库自动产生的id是使用jdbcTemplate模板的方法 但只要知道就行(mybatis代替)
因为一个user可能对应多个role 即一个userID可以对应多个roleID 所以在给关系表添加数据的时候,需要循环遍历对应user的roleID的数组 将其一 一对应的添加到数据库里
public void saveUserRoleRel(Long userId, Long[] roleIds) {
//一个user对应多个role 一个user有多个roleId
for (Long roleId : roleIds) {
jdbcTemplate.update("insert into sys_user_role values (?,?)",userId,roleId);
}
}
删除角色操作
根据页面传输携带的userId值来删除对应user的角色再删除user
判断用户有没有登录从而访问界面 首先利用拦截器线判断session域中有没有user对象 如果有则可以访问页面 如果没有这跳转到登录页面
首先从页面获得username和password传输到登录按钮提交的对应方法 然后userService调用userDao层查询username和password是否对应如果对应则封装成一个对象 然后保存到session域中 供拦截器检测 然后重定向到登录页面 值得注意的是如果username和password不匹配,jdbcTemplate操作数据库会抛出异常 需要接收
public User findByUsernameAndPassword(String username, String password) throws EmptyResultDataAccessException {
User user = jdbcTemplate.queryForObject("select * from sys_user where username = ? and password = ?",new BeanPropertyRowMapper(User.class),username,password);
return user;
}
@RequestMapping("/login")
public String login(String username, String password, HttpSession session){
User user = userService.login(username,password);
if (user!=null){
//登陆成功 将user存储到session域中
session.setAttribute("user",user);
return "redirect:/index.jsp";
}
return "redirect:/login.jsp";
}
SpringMVC的拦截器类似于Servlet开发中的过滤器Filter,用于处理器进行预处理和后处理
将拦截器按一定的顺序连结成一条链,这条链称为拦截器链(Interceptor Chain)。在访问被拦截的方法和字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现
创建拦截器实现HandlerLnterceptor接口
配置拦截器(在spring-mvc.xml里 配置拦截器 拦截器的执行的先后顺序是由在xml配置的顺序决定 下面的拦截器线执行)
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.itheima.interceptor.MyInterceptor2"/>
mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.itheima.interceptor.MyInterceptor1"/>
mvc:interceptor>
mvc:interceptors>
测试拦截效果
系統中异常包括两类:预期异常和运行时异第RuntimeException, 前者通过捕获异常从而获取异常信息,后 者主要通过规范代码开发!测试等手段减少运行时异常的发生
系統的Dao Service Controller出现都通过throws Exception向上拋出,最后由SpringMVC前端控制器交 由异常处理器进行异常处理,如下图:
使用SpringMVC提供的简单异常处理器SimpleMappingExceptionResolver
实现Spring的异常处理接口HandlerExceptionResolver自定义自己的异常处理器
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
默认异常跳转页面
<property name="exceptionMappings"> 可以自己规定什么异常 到什么页面处理
<map>
<entry key="ClassCastException" value="error1"/>
<entry key="MyException" value="error2"/>
map>
property>
bean>
方法中传入的 Exception e 代表了当前的异常是什么形式的
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
ModelAndView modelAndView = new ModelAndView();
if (e instanceof MyException){
modelAndView.addObject("info","自定义的异常");
}else if (e instanceof ClassCastException){
modelAndView.addObject("info","类转换异常");
}
modelAndView.setViewName("error");
return modelAndView;
}
Spring 框架的 AOP_w3cschool
AOP 为 Aspect Oriented Programming 的縮写,意思为面向切面编程, 是通过预编译方式和运行期动态代理实现程序功能的統一维护的一种技术
AOP 是 OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一 -个重界内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的名个部分进行抽离,从而使得业务逻辑各部分之间的耦合度降低,提育程序 的可重用性,同时提高了开发的效率
代理模式:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的媒介
实际上,AOP的底层是通过 Spring 提供的的动态代理技术实现的。在运行期间,Spring通过动态代理技木动态的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。
常用的动态代理技术
public static void main(String[] args) {
//目标对象 里面包含了一个save方法
final Target target = new Target();
//增强对象 想在save方法前或后执行的操作
Advice advice = new Advice();
//返回值 就是动态生成的代理对象
TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(
//目标对象的类加载器
target.getClass().getClassLoader(),
//目标对象相同的接口字节码对象数组
target.getClass().getInterfaces(),
new InvocationHandler() {
//调用代理的任何方法实质执行的都是invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//前置增强
advice.before();
//执行目标方法
Object invoke = method.invoke(target, args);
//后置增强
advice.afterReturning();
return invoke;
}
}
);
proxy.save();
}
public static void main(String[] args) {
//目标对象
final Target target = new Target();
//增强对象
Advice advice = new Advice();
//返回动态代理的对象 基于cglib
//1.设置增强器
Enhancer enhancer = new Enhancer();
//2.设置父类
enhancer.setSuperclass(Target.class);
//3.设置回调
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//执行前置
advice.before();
Object invoke = method.invoke(target, args);//执行目标
//执行后置
advice.afterReturning();
return invoke;
}
});
//4.创建代理对象
Target proxy = (Target) enhancer.create();
proxy.save();
}
Spring 的 AOP 实现底层就是对上面的动态代理的代码进行了封装,封装后我们只需要对需要关注的部分进行代码编写,井通过配置的方式完成指定目标的方法增强。
在正式讲解AOP 的操作之的,我们必须理解AOP 的相关术语,常用的术语如下:
Spring框架监控切入点方法的执行。一旦监控到切入点方法被执行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整代码的逻辑运行。
在spring在,框架会根据模板类是否实现了接口来决定采用哪种动态代理的方式
<bean id="target" class="com.itheima.aop.Target">bean>
<bean id="myAspect" class="com.itheima.aop.MyAspect">bean>
<aop:config>
<aop:aspect ref="myAspect">
<aop:pointcut id="myPointcut" expression="execution(public void *.itheima.aop.*.*(..))"/>
<aop:around method="around" pointcut-ref="myPointcut"/>
<aop:after method="after" pointcut-ref="myPointcut"/>
aop:aspect>
aop:config>
1.切点表达式的写法
execution([修饰符])返回值类型 包名.类名.方法名(参数)
@Component("MyAspect")
@Aspect //标注当前的MyAspect是一个切面类
public class MyAspect
<context:component-scan base-package="com.itheima.anno"/>
<aop:aspectj-autoproxy/>
@After("pointcut()")
public void after(){
System.out.println("最终增强.....");
}
//定义切点表达式
@Pointcut("execution(public void *.itheima.anno.*.*(..))")
public void pointcut(){
}
2.1什么是声明式事务控制
Spring 的声明式事务顾名思义就是采用声明的方式来处理事务。这里所说的声明,就是指在配置文件中声明 ,用在 Spring配置文件中声明式的处理事务来代著代码式的处理事务
声明式事务处理的作用
注意:Spring声明式事务控制底层就是AOP
声明式事务控制明确事项:
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
tx:attributes>
tx:advice
<aop:pointcut id="txPointcut" expression="execution(* com.itheima.service.impl.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
aop:config>
其中tx:method代表切点方法的事务参数的配置,;例如:
<tx:method name="*" isolation="DEFAULT" propagation="REQUIRED" timeout="-1" read-only="false"/>
在Service方法下
事务通知的配置(@Transactional(注解配置))
在AccountServiceImpl方法头添加**@Transactional(isolation = Isolation.DEFAULT)**代表该Service下的切面类都共用这个原则
@Transactional(isolation = Isolation.DEFAULT)
public class AccountServiceImpl implements AccountServic
而在Service下的切面类头上使用,利用就近原则切面类使用头上的原则
@Transactional(isolation = Isolation.READ_COMMITTED,propagation = Propagation.REQUIRED)
public void transfer
平台事务管理器配置(xml)
必须配置注解形式的平台事务管理器 不然无法执行相应注解形式的事务 事务注解驱动的配置
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
原始jdbc开发存在的问题如下:
应对上述问题给出的解决方案:
增删改查操作的Mybais映射配置
//模拟user对象
User user = new User();
user.setUsername("tom");
user.setPassword("abc");
//获得核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获得session过工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得session会话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行操作
sqlSession.insert("userMapper.save",user);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
参数可能会有多个类型
<select id="findAll" resultType="com.itheima.domain.User">
select * from user
select>
<insert id="save" parameterType="com.itheima.domain.User">
insert into user values(#{id},#{username},#{password})
insert>
<update id="update" parameterType="com.itheima.domain.User">
update user set username=#{username},password = #{password} where id = #{id}
update>
<update id="delete" parameterType="java.lang.Integer">
delete from user where id = #{id}
update>
mybatis – MyBatis 3 | 配置
environments 支持多配置数据库环境
其中,事务管理器 (transactionManager)
其中,数据源 (dataSource)类型有三种:
加载映射文件 加载方式有以下几种
mappers 下的mapper标签 可以配置多个mapper引用多个文件 用mapper映射
了解后三者
实际开发中,习惯将数据源的配置信息单独抽取成一个properties文件,在mybatis的配置文件李使用properties标签可以加载额外配置的properties文件
<properties resource="jdbc.properties">properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
dataSource>
environment>
environments>
类型别名是为Java类型设置一个短的名字。 自定义类的别名
<typeAliases>
<typeAlias type="com.itheima.domain.User" alias="user">typeAlias>
typeAliases>
常用API:SqlSessionFactory build(InputSream inputStream)
通过加载mybatis的核心文件的输入流的形式构建一个SqlSessionFactory对象
//获得核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获得session过工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
其中Resources工具类,这个类在org.apache.ibatis.io包中。Resource类帮助你从类路径下,文件系统或一个web URL在加载资源文件
而有了工厂对象 就可以造对象
sqlSessionFactory工厂对象可以创建会话对象SqlSession实例
有常用的以下两种
1.代理开发方式介绍 采用 Mybatis 的代理开发方式实现 DAO 层的开发,这种方式是我们后面进入企业的主流。
Mapper 接口开发方法只需要程序员编写Mapper 接口(相当于Dao 接口),由Mybatis框架根据接口定义创建接 口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法,
Mapper 投口开发需妥道后以下规范:
1、 Mapper.xml文件中的namespace与mapper接口的全限定名相同
2、Mapper接口方法名和Mapper.xml中定义的每个statement的sid相同
3、Mapper孩口方法的箱入參数类型和mapperxml中定义的每个sql的parameterType的类型相同
<mapper namespace="com.itheima.dao.UserMapper">
<select id="findAll" resultType="user">
select * from user
select>
<select id="findById" parameterType="int" resultType="user">
select * from user where id=#{id}
select>
mapper>
public interface UserMapper {
public List<User> findAll() throws IOException;
User findById(int id);
}
public class ServiceDemo {
public static void main(String[] args) throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List all = mapper.findAll();
User user = mapper.findById(1);
System.out.println(user);
System.out.println(all);
}
}
代理的方式不需要自己去实现接口内的方法 根据和UserMapper.xml里的sql语句返回值类型 和 输入类型和DAO层的接口类型一样,则mybatis会自动去填充 不需要直接实现接口内的方法
MyBatis的映射文件在,前面我们的SQL都是比较简单的,有时候业务逻辑复杂时,我们的SQL是动态变化的,此时前面学习在我们的SQL就不能满足需求了。
sql片段抽取
<sql id="selectUser">select * from usersql>
<select id="findByCondition" parameterType="user" resultType="user">
<include refid="selectUser">include>
<where> <-- where标签相当于1=1 则where标签会根据没有条件动态的查询 --!>
<if test="id!=0">
and id=#{id}
if>
<if test="username!=null">
and username=#{username}
if>
<if test="password!=null">
and password=#{password}
if>
where>
select>
choose(when, otherwise)
trim(where, set)
foreach
<select id="findByIds" parameterType="list" resultType="user">
<include refid="selectUser">include> ids in(?,?,?,?)
<where>
<foreach collection="list" open="id in(" close=")" item="id" separator=",">
#{id}
foreach>
where>
select>
无论是MyBatis在预处理句(PreparedStatement)在设置一个参数时,还是从结果集中取出的一个值时,都会用类型处理器将获取的值以合适的方式转换成Java类型。
也可以重写类型处理器或者创建自己的类型处理器来处理不支持的或非标准的类型。
具体实现 org.apache.ibatis.type.TypeHandler接口,或继承一个很便利的类 org.apache.ibatis.type.TypeHandler,然后可以选择地将它映射到一个JDBC类型。例如:一个Java中的Date数据类型,在存入数据库的时候存成1970年至今的毫秒数,取出来时转换成Java的Date。即Java的Date与数据库的varchar毫秒值之间的转换
开发步骤:
关于MyBatisX爆红 是因为给类定义别名的时候 在其他模块定义了相同的别名
原来我定一个两个user类,在不同的modul下 需要修改 别名
MyBatis可以使用第三方插件对功能进行扩展,分页助手PageHelper是将分页的复杂操作进行封装,使用简单的方式即可获得分页的相关数据
开发步骤:
导入通用PageHelper的坐标
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelperartifactId>
<version>3.7.5version>
dependency>
<dependency>
<groupId>com.github.jsqlparsergroupId>
<artifactId>jsqlparserartifactId>
<version>0.9.1version>
dependency>
在mybatis核心配置文件中配置PageHelper插件
测试
//设置分页相关参数 当前页 每页显示的数目
PageHelper.startPage(1, 3);
//保存对象
List userList = mapper.findAll();
for (User user : userList) {
System.out.println(user);
}
<resultMap id="orderMap" type="order">
<id column="oid" property="id">id>
<result column="orderTime" property="orderTime">result>
<result column="total" property="total">result>
<association property="user" javaType="useres">
<id column="uid" property="id">id>
<result column="username" property="username">result>
<result column="password" property="password">result>
<result column="birthday" property="birthday">result>
association>
resultMap>
<select id="findAll" resultMap="orderMap">
select *, o.oid oid from order o,user u where o.uid = u.id
select>
<resultMap id="UserMap" type="useres">
<id column="uid" property="id">id>
<result column="username" property="username">result>
<result column="password" property="password">result>
<result column="birthday" property="birthday">result>
<collection property="orderList" ofType="order">
<id column="oid" property="id">id>
<result column="orderTime" property="orderTime">result>
<result column="total" property="total">result>
collection>
resultMap>
<select id="findAll" resultMap="UserMap">
select *, o.id oid
from user u,
order o
where u.id = o.uid
select>
多对多查询的需求:查询用户同时查询该用户的所有角色
多对多关系 需要新建一个表
<resultMap id="userRoleMap" type="useres">
<id column="userId" property="id">id>
<result column="username" property="username">result>
<result column="password" property="password">result>
<result column="birthday" property="birthday">result>
<collection property="roleList" ofType="role">
<id column="roleId" property="id">id>
<result column="roleName" property="roleName">result>
<result column="roleDesc" property="roleDesc">result>
collection>
resultMap>
<select id="findUserAndRole" resultMap="userRoleMap">
select *
from user u,
role r,
userrole ur
where u.id = ur.userId
and ur.roleId = r.id
select>
注解开发越来越流行,使用注解形式减少了xml配置 但是值得注意的是 对应简单的操作建议使用注解形式 而对应逻辑比较复杂的操作还是建议使用xml的形式
实现复杂关系映射之前我们可以在映射文件中通过配置来实现,使用注解开发后,我们可以使用@Results注解,@Result注解,@One注解组合完成复杂关系的配置
使用注解形式开发查询订单的对应信息和订单用户信息
//两张表一起查
@Select("select *, o.oid oid from order o,user u where o.uid = u.id")
@Results({
@Result(column = "oid",property = "id"),
@Result(column = "orderTime",property = "orderTime"),
@Result(column = "total",property = "total"),
@Result(column = "uid",property = "user.id"),
@Result(column = "username",property = "useres.username"),
@Result(column = "password",property = "useres.password"),
})
List<Order> findAll();
############################################################################################################
// 先查一张表再查另一张表
@Select("select *, o.oid oid from order o,user u where o.uid = u.id")
@Results({
@Result(column = "oid",property = "id"),
@Result(column = "orderTime",property = "orderTime"),
@Result(column = "total",property = "total"),
@Result(
property = "user",//要封装的属性名称
column = "uid", //跟据哪个字段去查询user表的数据
javaType = User.class,//要封装的实体类型
//select属性 代表查询哪个接口的方法获得数据
//根据查询user接口里查询user id 的方法返回id 给column 从而获得user数据
one = @One(select = "查询user表的id的方法")
-----@Select("select * from user where id=#{id}")
-----User findById(int id)
)
})
List<Order> findAll();
注解形式相比与xml方式更加方便 查询结果和作用相同
<resultMap id="orderMap" type="order">
<id column="oid" property="id">id>
<result column="orderTime" property="orderTime">result>
<result column="total" property="total">result>
<association property="user" javaType="useres">
<id column="uid" property="id">id>
<result column="username" property="username">result>
<result column="password" property="password">result>
<result column="birthday" property="birthday">result>
association>
resultMap>
<select id="findAll" resultMap="orderMap">
select *, o.oid oid from order o,user u where o.uid = u.id
select>
@Select("select * from user")
@Results({
//id=true 表明该列是主键
@Result(id=true, column = "id",property = "id"),
@Result(column = "username",property = "username"),
@Result(column = "password",property = "password"),
@Result(
property = "orderList",//要封装的属性名称
column = "id", //跟据哪个字段去查询user表的数据
javaType = List.class,//要封装的实体类型
//select属性 代表查询哪个接口的方法获得数据
//根据查询order接口里查询user id 的方法返回user id 给column 从而获得user对应的order表数据
many = @Many(select = "查询order表的user id的方法")
-------@Select("select * from order where uid=#{uid}")
-------List findByUid(int uid)
)
})
List findAll();
存在一个中间表
一个user可能对应多个角色 而一个角色又可以对应多个user
多对多查询的需求:查询用户同时查询该用户的所有角色
@Select("select * from user")
@Results({
//id=true 表面该列是主键
@Result(id=true, column = "id",property = "id"),
@Result(column = "username",property = "username"),
@Result(column = "password",property = "password"),
@Result(
property = "roleList",//要封装的属性名称
column = "id", //跟据哪个字段去查询user表的数据
javaType = List.class,//要封装的实体类型
//select属性 代表查询哪个接口的方法获得数据
//根据查询UserAndOrder接口里查询user id 的方法返回与role id对应user id 给column
// 从而获得user对应的role表数据
many = @Many(select = "查询UserAndRole表的user id的方法")
----@Select("select * from UserAndRole ur,role r where ur.roleId=r.id and ur.userId=#{id}")
----List<Role> findByUid(int uid);
)
})
List<User> findUserAndRole();
<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">
<context:component-scan base-package="com.itheima">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller">context:exclude-filter>
context:component-scan>
beans>
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties">properties>
<typeAliases>
<typeAlias type="com.itheima.domain.Account" alias="account">typeAlias>
typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}">property>
<property name="url" value="${jdbc.url}">property>
<property name="username" value="${jdbc.username}">property>
<property name="password" value="${jdbc.password}">property>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/itheima/mapper/AccountMapper.xml">mapper>
mappers>
configuration>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.itheima.controller">context:component-scan>
<mvc:annotation-driven>mvc:annotation-driven>
<bean id="resourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/">property>
<property name="suffix" value=".jsp">property>
bean>
<mvc:default-servlet-handler>mvc:default-servlet-handler>
beans>
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.AccountMapper">
<insert id="save" parameterType="account">
insert into ssm values(#{id},#{name},#{money})
insert>
<select id="findAll" resultType="account">
select * from ssm
select>
mapper>
在配置mapper映射文件的时候在resources目录下创建包和配置文件的格式为:com/itheima/mapper/xxxxxx.xml 中间不能用点来分割 否则在运行时会找不到资源文件
起别名的方式有两种 但是在用web界面的情况下 最好使用根源目录的配置方式 不要使用包扫描的方式 否则页面会丢失
将数据源和外部资源文件交给spring来配置
将session工厂的配置交给spring :工厂里需要引入数据源和mybatis的其他配置
由spring创建 声明式事务控制
<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">
<context:component-scan base-package="com.itheima">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller">context:exclude-filter>
context:component-scan>
<context:property-placeholder location="classpath:jdbc.properties">context:property-placeholder>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}">property>
<property name="jdbcUrl" value="${jdbc.url}">property>
<property name="user" value="${jdbc.username}">property>
<property name="password" value="${jdbc.password}">property>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource">property>
<property name="configLocation" value="classpath:sqlMapConfig-spring.xml">property>
bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.itheima.mapper">property>
bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource">property>
bean>
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="*"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.itheima.service.impl.*.*(..))">aop:advisor>
aop:config>
beans>
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountMapper accountMapper;
@Override
public void save(Account account) throws IOException {
//由spring来创建工厂对象 简化了代码
accountMapper.save(account);
}
@Override
public List findAll() throws IOException {
//由spring来创建工厂对象 简化了代码
return accountMapper.findAll();
}
}
扫描mapper所在的包 为mapper创建实现类 会为mapper创建实现放入容器里 所以才能将AccountMapper注入到容器里
参考:ssm的架构及整合说明 - twoheads - 博客园 (cnblogs.com)
一般来说 ssm中
ssm框架里需要的配置文件有:
applicationContext.xml通常包括的内容有:
组件扫描(主要是扫描整个项目包下的spring注解 但需要排除controller(spring-mvc的web层的控制器)因为这个需要spring_mvc的配置文件自己扫描)
数据源(配置数据库的信息)
配置sessionFactory 配置会话工厂 将工厂的创建注入到spring容器里简化service层每次使用sessionFactory 的代码
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource">property>
<property name="configLocation" value="classpath:sqlMapConfig-spring.xml">property>
bean>
特别注意的是使用mapper扫描器在扫描mapper的包后在spring容器里注入了mapper的对应实体类 可以直接使用mapper对象来调用方法
@Autowired
private AccountMapper accountMapper;
@Override
public void save(Account account) throws IOException {
//由spring来创建工厂对象 简化了代码
accountMapper.save(account);
}
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.itheima.mapper">property>
bean>
配置事务控制 在原有的操作上进行增强操作或者识别
配置处理器映射器
<mvc:annotation-driven>mvc:annotation-driven>
组件扫描(扫描controller层 对应的mvc注解)
视图解析器
适配器
开放静态资源访问权限
主要的数据源配置到spring配置文件中 将数据放在spring容器里更方便获取
包括了少量文件配置是为了给domain实体类器别名 和批量包扫描包下对应的实体类
<typeAliases>
<typeAlias type="com.itheima.domain.Account" alias="account">typeAlias>
typeAliases>