取值范围 | 说明 | 生命周期 |
---|---|---|
singleton | 默认的,单例的 | 对象创建:应用加载,创建容器时对象就被创建了 对象运行:只要容器在,对象一直活着 对象销毁:当应用卸载,销毁容器时,对象就被销毁了 |
prototype | 多例的 | 对象创建:当使用对象时,创建新的对象实例 对象运行:只要对象在使用中,就一直活着 对象销毁:当对象长时间不用时,被Java的垃圾回收器回收了 |
request | WEB项目中,Spring创建一个Bean的对象,将对象存到request域中 | |
session | WEB项目中,Spring创建一个Bean的对象,将对象存到session域中 | |
global session | WEB项目中,应用在Portlet环境中,如果没有Portlet环境,那么globalSession相当于session |
<bean id="factory" class="com.ithemima.factory.DynamicFactory">bean>
<bean id="userDao" factory-bean="factory" factory-method="getUserDao" >bean>
set方法 Service内部需要Dao 需要文件配置
<bean>
<property name="userDao" ref="" value="" >property>
(u大小转成小写 对应Service中setUserDao)
(ref 对象类型引用)
(value 普通数据类型)
bean>
如果是集合类型 以 List
为例
<bean>
<property>
<list>
<value>xxxvalue>
<value>xxxvalue>
list>
property>
bean>
Map
<bean>
<property>
<Map>
<entry key="" value-ref="{Bean的id}">entry>
Map>
property>
bean>
内容 | 含义 |
---|---|
|
标签 |
id属性 | 在容器中Bean实例的唯一标识,不允许重复 |
class属性 | 要实例化的Bean的全限定名 |
scope属性 | Bean的作用范围,常用是Singleton(默认)和prototype |
属性 |
属性注入 |
name属性 | 属性名称 |
value属性 | 注入的普通属性值 |
ref属性 | 注入的对象引用值 |
|
标签 |
|
标签 |
|
标签 |
|
有参构造注入 |
标签 |
导入其他的Spring的分文件 |
String
类型数据 id 可以获取相同类型的数据
如xxx.class 返回值为该类 不能获取多个相同类型的数据ApplicationContext app = new ClasspathXmlApplicationContext("xml文件");
app.getBean("id");
app.getBean(Class);
pom中 dependencies配置
ComboPoolDataSource dataSource = new ComboPoolDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/");
dataSource.setUser("root");
dataSource.setPassword("root");
Connection connection = dataSource.getConnection();//连接数据源
connection.close();//归还数据源
解耦合 读取配置文件
ResourceBundle = ResourceBundle.getBundle("jdbc");//resource下jdbc.properties文件
String driver = rb.getString("jdbc.driver");//Key
String url = rb.getString("jdbc.url");
String username = rb.getString("jdbc.username");
String password = rb.getString("jdbc.password");
ComboPoolDataSource dataSource = new ComboPoolDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
Connection connection = dataSource.getConnection();//连接数据源
connection.close();//归还数据源
先配置
ApplicationContext app = new ApplicationCOntext();
DataSource dataSource = app.getBean(DataSource.class);
Connection connection = dataSource.getConnection();
connection.close();
Spring容器加载properties文件
<context:property-placeholder location="xx.properties">context:property-placeholder>
<property name="" value="${key}" />
注解 | 说明 |
---|---|
@Component | 使用在类上实例化Bean |
@Controller | 使用在Web层类上用于实例化Bean |
@Service | 使用在service层类上用于实例化Bean |
@Repository | 使用在dao层类上用于实例化Bean |
@Autowired | 使用在字段上用于根据类型依赖注入 |
@Qualifier | 结合@Autowired一起使用,用于根据名称进行依赖注入 |
@Resource | 相当于@Autowired+@Qualifier,按照名称进行注入 |
@Value | 注入普通属性 |
@Scope | 标注Bean的作用范围 |
@PostConstruct | 使用在方法上标注该方法是Bean的初始化方法 |
@PreDestroy | 使用在方法上标注该方法是Bean的销毁方法 |
注意:
使用注解进行开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean需要进行扫描以便识别使用注解配置的类、字段和方法
<context:component-scan base-package="">context:component-scan>
使用上面的注解还不能全部替代xml配置文件,还需要使用注解替代的配置如下:
注解 | 说明 |
---|---|
@Configuration | 用于指定当前类是一个Spring配置类,当创建容器时会从该类上加载注解 |
@ComponentScan | 用于指定Spring在初始化容器时要扫描的包 作用和在Spring的xml配置文件中的 一样 |
@Bean | 使用在方法上,标注将该方法的返回值存储到Spring容器中 |
@PropertySource | 用于加载.properties 文件中的配置 |
@Import | 用于导入其他配置类 |
Spring提供了一个监听器ContextLoaderListener,对获取上下文功能进行封装,该监听器
内部加载Spring配置文件,创建应用上下文对象,并存储到ServletContext域中,提供了一个客户端工具WebApplicationContextUtils供使用者获得应用上下文对象
需求:客户端发起请求,服务器端接受请求,执行逻辑并进行视图跳转
开发步骤:
流程:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4yXtMMR1-1632051628434)(C:\Users\Superclass\IdeaProjects\demo01\src\main\resources\SpingLearn\SpringMVC.jpg “SpringMVC”)]
@RequestMapping
作用:用于建立请求URL和处理请求方法之间的对应关系
位置:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UserController{
//访问路径为 http://localhost:8080/user/save
@RequestMapping("/save")
public String save(){
return "/success.jsp"; //注意需要`/` 否则路径为相对路径会找不到资源
}
}
属性:
form
只能回get/post
)SpringMVC相关组件
SpringMVC注解和配置
REDIRECT_URL_PREFIX="redirect:"
FORWARD_URL_PREFIX="forward:"
prefix="";
suffix="";
1) 页面跳转
@RequestMapping("/quick")
public String quickMethod(){
return "index";
}
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views" />
<property name="suffix" value=".jsp" />
bean>
转发地址 /WEB-INF/views/index.jsp
@RequestMapping("/quick")
public ModelAndView quickMethod(){
/*
* Model: 模型 作用:封装数据
* View: 视图 作用:展示数据
*/
ModelAndView modelAndView = new ModelAndView();
//设置模型数据
modelAndView.addObject("username","itcast"); //任意数据
//设置视图
modelAndView.setViewName("index");
return modelAndView;
}
参数为ModelAndView
@RequestMapping("/quick2")
public ModelAndView quickMethod(ModelAndView modelAndView){ //注入
/*
* Model: 模型 作用:封装数据
* View: 视图 作用:展示数据
*/
//设置模型数据
modelAndView.addObject("username","itcast"); //任意数据
//设置视图
modelAndView.setViewName("index");
return modelAndView;
}
ModelAndView可以拆开,单取Model
Web基础阶段,客户端访问服务器端,如果想直接回写字符串作为响应体返回的话,只需要使用response.getWriter().print("Hello World");
即可,
那么在Controller中想直接回写字符串该怎样呢?
@RequestMapping("/quick3")
public void save(HttpServletResponse response) throws IOException { //回写
response.getWriter().print("hello itcast");
}
如何解耦合
需要@ResponseBody
注解告知SpringMVC框架,方法返回的字符串不是跳转,是直接在http响应体中返回
@RequestMapping("/quick3")
@ResponseBody //回写就要加
public void save(){
return "hello itcast";
}
如何返回json数据
@RequestMapping("/quick3")
@ResponseBody //回写就要加
public void save(){
User user = new User();
user.setUsername("李四");
user.setAge(30);
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(user);
return json;
}
手动转很累
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
bean>
list>
property>
bean>
@RequestMapping("/quick3")
@ResponseBody //回写就要加
public User save(){ //利用[适配器]
user.setUsername("李四");
user.setAge(30);
return user;
}
可以使用mvc的注解驱动代替上述xml配置
<mvc:annotation-driven xmlns="http://www.springframework.org/schema/cache">mvc:annotation-driven>
forward:
转发redirect
重定向客户端请求参数的格式是: name=value&name=value...
即GET
服务器端要获取请求的参数,有时还需要进行数据的封装,SpringMVC可以接受接收如下类型的参数:
Controller中的业务方法的参数名称要与请求参数的name一致,参数值会自动映射匹配
@RequestMapping("/quick4")
@ResponseBody //回写就要加
public void userParams(String name, int age){
System.out.println(name);
System.out.println(age);
}
Controller中的业务方法的POJO参数的属性名与请求参数的name一致,参数值会自动映射匹配
@RequestMapping("/quick5")
@ResponseBody
public void userParams(User user){
System.out.println(user);
}
Controller中的业务方法数组名称与请求参数的name一致,参数值会自动映射
@RequestMapping("/quick5")
@ResponseBody
public void userParams(String[] strs){
System.out.println(Arrays.asList(strs));
}
获得集合参数时,要将集合参数包装到一个POJO中才可以
当使用ajax提交时,可以指定contenttype为json形式,那么在方法参数位置使用@RequestBody
可以直接接收集合数据而无需使用POJO进行包装
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Titletitle>
<script src="${pageContext.request.contextPath}/js/jquery-3.3.1.js">script>
<script>
var userList = new Array();
userList.push({username:"张三",age:18});
userList.push({username:"李四",age:20});
$.ajax({
type:"POST",
url:"${pageContext.request.contextPath}/user/quick6",
data:JSON.stringify(userList),
contentType:"application/json;charset=utf-8"
});
script>
head>
<body>
body>
html>
import org.springframework.web.bind.annotation.ResponseBody;
@RequestMapping("/quick6")
@ResponseBody
public void userParams(@ResponseBody List < User > userList)throws IOException{
System.out.println(userList);
}
mvc配置
<mvc:resources mapping="/js/**" location="/js/"/>
或者
<mvc:default-servlet-handler/>
当POST请求时,数据会出现乱码,我们可以设置一个过滤器来进行编码的过滤
配置filter
<filter>
<filter-name>
CharacterEncodingFilter
filter-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>
当请求的参数名称与Controller的业务方法名称不一致时,就需要通过@RequestParam注解显示的绑定
<form action="${pagaContext.request.contextPath}/test" method="post">
<input type="text" name="name"><br>
<input type="submit" value="提交"><br>
form>
@RequestMapping("/quick6")
@ResponseBody
public void userParams(@RequestParam("name") String username)throws IOException{
System.out.println(username);
}
注解@RequestParam
有如下参数可以使用
Restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束。主要用于客户端和服务端交互类的软件,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存机制。
Restful风格的请求是使用“URL+请求方式”表示一次请求目的的,HTTP协议里面四个表示操作方式的动词如下:
/user/11
可以写成/user/{name}
,占位符{name}
对应的就是1的值。在业务方法中我们可以使用@PathVariable
注解进行占位符的匹配获取工作import org.springframework.web.bind.annotation.PathVariable;
@RequestMapping("/user/{name}")
@ResponseBody
public void userParams(@PathVariable(value="name", required = true) String name){
System.out.println(name);
}
自定义类型转换器的开发步骤
import javax.persistence.Converter;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateConverter implements Converter<String, Date> {
public Date converter(String dateStr) {
//将日期字符串转换成日期对象
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date = simpleDateFormat.parse(dateStr);
return date;
}
}
<mvc:annotation-drivern conversion-services="conversionService">mvc:annotation-drivern>
<bean class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="{当前路径}.converters.DateConverters">bean>
list>
property>
bean>
SpringMVC支持使用原始ServletAPI对象作为控制器方法的参数进行注入,常用的对象如下:
@RequestHeader
使用@RequestHeader
可以获得请求头信息,相当于web中学习的request.getHeader(name)
@RequestHeader
注解的属性如下:
import org.springframework.web.bind.annotation.RequestHeader;
@RequestMapping("/user/requestheader")
@ResponseBody
public void userParams(@RequestHeader(value = "User-Agent") String user_agent){
System.out.println(user_agent);
}
@CookieValue
使用@CookieValue
可以获得指定Cookie的值
@CookiValue
注解的属性如下:
import org.springframework.web.bind.annotation.CookieValue;
@RequestMapping("/user/cookievalue")
@ResponseBody
public void userParams(@CookieValue(value = "JSESSIONID") String jsessionId){
System.out.println(jsessionId);
}
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8">property>
<property name="maxUploadSource" value="500000">property>
bean>
@RequestMapping("/user/file")
@ResponseBody
public void userParams(MultipartFile uploadFile) throws IOException{//参数名要对应
String originalFilename = uploadFile.getOriginalFilename();//获得原始文件名称
uploadFile.transferTo(new File("C:\\upload\\"+originalFilename));//存文件
}
@RequestMapping("/user/file")
@ResponseBody
public void userParams(MultipartFile[] uploadFiles) throws IOException{//参数名要对应
for(MultipartFile file:uploadFile){
String originalFilename = file.getOriginalFilename();//获得原始文件名称
file.transferTo(new File("C:\\upload\\"+originalFilename));//存文件
}
}
MVC实现数据请求方式
@RequestParam
和@PathVariable
@RequestHeader
和@CookieValue
他是spring框架中提供的一个对象,是对原始繁锁的Jdbc API对象的简单封装。spring框架为我们提供了很多的操作模板类。例如:操作关系型数据的JdbcTemplate和HibernateTempalet,操作
nosql数据的RedisTemplate,操作消息队列的JmsTemplate等等。
public class Account{
private String name;
private double money;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"name='" + name + '\'' +
", money=" + money +
'}';
}
}
import org.springframework.jdbc.core.JdbcTemplate;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JdbcTemplateTest {
@Test
public void test01() {
//创建数据源对象
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUser("root");
dataSource.setPassword("root");
JdbcTemplate jdbcTemplate = new JdbcTemplate();
//设置数据源对象 知道数据库在哪(Connection)
jdbcTemplate.setDataSource(dataSource);
//执行操作
int row = jdbcTemplate.update("insert into account values(?,?)", "tom", 5000);
System.out.println(row);
}
}
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test" />
<property name="user" value="root" />
<property name="password" value="root" />
bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
bean>
import org.apache.catalina.core.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
public class JdbcTemplateTest {
@Test
public void test02() {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
JdbcTemplate jdbcTemplate = app.getBean(JdbcTemplate.class);
int row = jdbcTemplate.update("insert into account values(?,?)", "tom", 5000);
System.out.println(row);
}
}
数据库语句不同
CRUD都是update方法
import com.example.demo01.reflect.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class JdbcTemplateCRUDTest {
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
public void testUpdate(){
jdbcTemplate.update("update account set money=? where name=?",10000,"tom");
}
@Test
public void testDelete(){
jdbcTemplate.update("delete from account where name=?","tom");
}
}
查询
import com.example.demo01.beans.Account;
import com.example.demo01.reflect.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class JdbcTemplateCRUDTest {
@Autowired
private JdbcTemplate jdbcTemplate;
//查一个
@Test
public void testQueryOne() {
Account account = jdbcTemplate.queryForObject("select * from account where name=?", new BeanPropertyRowMapper<Account>(Account.class), "tom");
System.out.println(account);
}
//全查
@Test
public void testQueryAll() {
List<Account> accountList = jdbcTemplate.query("select * from account", new BeanPropertyRowMapper<Account>(Account.class));//<实体泛型>(字节码)
System.out.println(accountList);
}
//统计数量
@Test
public void testQueryCount() {
Long count = jdbcTemplate.queryForObject("select count(*) from account", Long.class);
System.out.println(count);
}
}
SpringMVC的拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理
将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(Interceptor Chain)。在访问被拦截的方法或
字段时,拦截器中的拦截器会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。
区别 | 过滤器(Filter) | 拦截器(Interceptor) |
---|---|---|
使用范围 | 是Servlet规范中的一部分,任何Java Web工程都可以使用 | 是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用 |
拦截范围 | 在url-pattern中配置了/*之后,可以对所有要访问的资源拦截 | 在 |
自定义拦截器有一下步骤:
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
//在目标方法执行前 执行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("preHandler.....");
String param = request.getParameter("param");
if("yes".equals(param)){
return true;
}
else {
request.getRequestDispatcher("/error.jsp").forward(request,response);
return false;//服务停止
}
}
//在目标方法执行后 视图对象返回之前执行
public void postHandler(HttpServletRequest request, HttpServletResponse, Object handler, ModelAndView modelAndView) {
System.out.println("postHandler.....");
}
//在流程都执行完毕后执行
public void after(HttpServletRequest request, HttpServletResponse response,Object handler, Exception ex){
System.out.println("afterCompletion.....");
}
}
配置拦截器
<mvc:interceptors xmlns="http://www.springframework.org/schema/mvc">
<mvc:interceptor>
<mvc:mapping path="/**"/>
mvc:interceptor>
mvc:interceptors>
Controller层
import org.springframework.web.servlet.ModelAndView;
public class TargetController() {
@RequestMapping("/target")
public ModelAndView show(){
System.out.println("目标资源执行.....");
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name","itcast");
modelAndView.setViewName("index");
return modelAndView;
}
}
方法 | 说明 |
---|---|
preHandle() | 方法将在请求处理之前进行调用,该方法的返回值是布尔值Boolean类型的,当它返回为false时,表示请求结束,后续的Interceptor和Controller都不会再执行;当返回值为true时就会继续调用下一个INterceptor的preHandle方法 |
postHandle() | 该方法是在当前请求进行处理之后被调用,前提是preHandle方法的返回值为true时才能被调用,且它会在DispatcherServlet进行视图返回值渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的ModelAndView对象进行操作 |
afterCompletion() | 该方法在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行,前提是preHandle方法的返回值为true时才能被调用 |
系统中的异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过gui’fan代码开发,测试等手段减少运行时异常的发生。
系统的Dao、Service、Controller出现都通过throws Exception
向上抛出,最后由SpringMVC前端控制器交由异常处理器进行异常处理。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M5hUumy6-1632051628440)(C:\Users\Superclass\IdeaProjects\demo01\src\main\resources\SpingLearn\exception.png)]
SimpleMappingExceptionResolver
HandlerExceptionResolver
自定义自己的异常处理器SimpleMappingExceptionResolver
SpringMVC已经定义好了该类型转换器,在使用时可以根据项目情况进行相应异常与视图的映射配置
bean>
AOP为Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
AOP是OOP的延续,是软件开发中的一个特定,也是Spring框架中的一个重要内容,是函数式编程的一种衍生泛型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的
耦合度降低,提高程序的可重用性,同时提高了开发的效率。
实际上,APO的底层是通过Spring提供的动态代理技术实现的。在运行期间,Spring通过动态代理技术,动态地生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。
常用的动态代理技术
public interface TargetInterface{
public void save();
}
public class Target implements TargetInterface{
public void save(){
System.out.println("save running .....");
}
}
public class Advice{
public void before(){
System.out.println("前置增强。。。");
}
public void afterRuning(){
System.out.println("后置增强。。。");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
final Target target = new Target();
final Advice advice = new Advice();
Proxy.newProxyInstance(
target.getClass().getClassLoader(), //目标对象类加载器
target.getClass().getInterface(), //目标对象相同的接口字节码对象数组
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 class Target{
public void save(){
System.out.println("save running .....");
}
}
public class Advice{
public void before(){
System.out.println("前置增强。。。");
}
public void afterRuning(){
System.out.println("后置增强。。。");
}
}
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
//目标对象
final Target target = new Target();
//增强对象
final 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.afterRunning();
return invoke;
}
});
//4. 创建代理对象
Target proxy = (Target) enhancer.create();
}
}
Spring的AOP实现底层就是对上面的动态代理的代码进行了封装,封装之后我们只需要对需要关注的部分进行代码编写,并通过配置的方式完成指定目标的方法增强。
常用术语如下:
<bean id="target" class="{path}.Target">bean>
<bean id="myAspect" class="{path}.myAspect">bean>
<aop:config>
<aop:aspect ref="myAspect">
<aop:before method="before" pointcut="execution(public void {path}.Target.save())">aop:before>
<aop:around method="around" pointcut="execution(* com.example.aop.*.*(..))">aop:around>
<aop:after-throwing method="afterThrowing" pointcut="execution(* com.example.aop.*.*(..))">aop:after-throwing>
<aop:after method="afterThrowing" pointcut="execution(* com.example.aop.*.*(..))">aop:after>
aop:aspect>
aop:config>
import com.example.demo01.reflect.Autowired;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Autowired
private TargetInterface target;
@Test
public void test1(){
target.save();
}
}
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAspect {
public void before() {
System.out.println("前置增强...");
}
public void afterRunning(){
System.out.println("后置增强...");
}
public Object around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("环绕前增强。。。。");
Object proceed = pjp.proceed();
System.out.println("环绕后增强。。。。");
return proceed;
}
public void afterThrowing(){
System.out.println("异常抛出增强。。。。。。");
}
public void after(){
System.out.println("最终增强。。。。。。");
}
}
通知配置语法:
名称 | 标签 | 说明 |
---|---|---|
前置通知 |
|
用于配置前置通知。指定增强方法在切入点之前执行 |
后置通知 |
|
用于配置后置通知。指定增强的方法在切入点之后执行 |
环绕通知 |
|
用于配置环绕通知。指定增强方法在切入点之前和之后都执行 |
异常抛出通知 |
|
用于配置异常抛出通知。指定增强的方法在出现异常时执行 |
最终通知 |
|
用于配置最终通知。无论增强方式执行是否有异常都会执行 |
当多个增强的切点表达式相同时,可以将切点表达式进行抽取,在增强中使用pointcut-ref属性代替pointcut属性来引用抽取后的切点表达式。
基于注解的AOP开发步骤:
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component("myAspect")
@Aspect //标注当前的MyAspect是一个切面类
public class myAspect {
@Before("execution(* com.example.aop.*.*(..))")
public void before() {
System.out.println("前置增强...");
}
public void afterRunning() {
System.out.println("后置增强...");
}
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕前增强。。。。");
Object proceed = pjp.proceed();
System.out.println("环绕后增强。。。。");
return proceed;
}
public void afterThrowing() {
System.out.println("异常抛出增强。。。。。。");
}
public void after() {
System.out.println("最终增强。。。。。。");
}
}
名称 | 标签 | 说明 |
---|---|---|
前置通知 | @Before |
用于配置前置通知。指定增强方法在切入点之前执行 |
后置通知 | @AfterRunning |
用于配置后置通知。指定增强的方法在切入点之后执行 |
环绕通知 | @Around |
用于配置环绕通知。指定增强方法在切入点之前和之后都执行 |
异常抛出通知 | @AfterThrowing |
用于配置异常抛出通知。指定增强的方法在出现异常时执行 |
最终通知 | @After |
用于配置最终通知。无论增强方式执行是否有异常都会执行 |
在切面内方法上使用@Pointcut
注解定义切点表达式
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component("myAspect")
@Aspect //标注当前的MyAspect是一个切面类
public class myAspect {
@Before("MyAspect.myPoint()")
public void before() {
System.out.println("前置增强...");
}
@Pointcut("execution(* com.example.aop.*.*(..))")
public void myPoint(){}
}
PlatformTransactionManager接口是spring的事务管理器,它里面提供了我们常用的操作事务的方法
方法 | 说明 |
---|---|
TransactionStatus getTransaction(TransactionDefination defination) | 获取事务的状态信息 |
void commit (TransactionStatus status) | 提交事务 |
void rollback(TransactionStatus status) | 回滚事务 |
注意:PlatformTransactionManager 是接口类型,不同的Dao层技术则有不同的实现类
TransactionDefinition是事务的定义信息对象,里面有如下方法:
方法 | 说明 |
---|---|
int getIsolationLevel() | 获得事务的隔离级别 |
int getPropogationBehavior() | 获得事务的传播行为 |
int getTimeout() | 获得超时时间 |
boolean isReadOnly() | 是否只读 |
值 | 说明 |
---|---|
REQUIRED | 如果当前没有事务,就新建一个事务。如果存在一个事务,加入到 这个事务中,一般的选择(默认值) |
SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务) |
MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常 |
REQUERS_NEW | 新建事务,如果当前在事务中,把当前事务挂起 |
NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起 |
NEVER | 以非事务方式运行,如果当前存在事务,抛出异常 |
NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行REQUIRED类似的操作 |
超时时间 | 默认值是-1,没有超时限制。如果有,以秒为单位进行设置 |
是否只读 | 建议查询时设置为只读 |
A调B,B看A有没有事务
Transaction接口提供的是事务具体的运行状态,方法介绍如下
方法 | 说明 |
---|---|
boolean hasSavepoint() | 是否存储回滚点 |
boolean isCompleted() | 事务是否完成 |
boolean isNewTransaction() | 是否是新事务 |
boolean isRollbackOnly() | 事务是否回滚 |
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9tJaAg2Y-1632051628442)(C:\Users\Superclass\IdeaProjects\demo01\src\main\resources\SpingLearn\事务.png)]
<tx:advice id="txAdice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false">tx:method>
<tx:method name="save*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false">tx:method>
tx:attributes>
tx:advice>
import com.example.demo01.reflect.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service("accountService")
@Transactional()
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
oublic
void transfer(String outMan, String inMan, double money) {
accountDao.out(outMan., money);
accountDao.in(inMan, money);
}
}
开发步骤:
mapping.xml
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="userMapper">
<select id="findAll" resultType="com.example.domain.User">
select * from user
select>
mapper>
核心文件约束
sqlMapConfig
DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test/"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/example/mapper/UserMapper.xml">mapper>
mappers>
configuration>
测试
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
import java.util.List;
public class MyBatisTest {
@Test
public void test01() {
//获取核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获得session工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得session回话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行操作 参数:namespace+id
List<User> userList = sqlSession.selectList("userMapper.findAll");
//打印数据
System.out.println(userList);
//释放资源
sqlSession.close();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-50NdpkY0-1632051628444)(C:\Users\Superclass\IdeaProjects\demo01\src\main\resources\SpingLearn\MyBatis映射文件.png)]
mapping.xml
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="userMapper">
<insert id="save" parameterType="com.example.domain.User">
insert into user values(#{id},#{username},#{password})
insert>
<select id="findAll" resultType="com.example.domain.User">
select * from user
select>
mapper>
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
import java.util.List;
public class MyBatisTest {
@Test
public void test02() {
//模拟user对象
User user = new User();
user.setUsername("张三");
user.setPassword("123")
//获取核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获得session工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得session回话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行操作 参数:namespace+id
sqlSession.insert("userMapper.save",user);
//mybatis默认事务不提交 要执行插入操作,就要提交数据
sqlSession.commit();
//打印数据
System.out.println(userList);
//释放资源
sqlSession.close();
}
}
#{实体属性名}
方式引用实体中的属性值sqlSession.insert("命名空间.id",实体对象);
sqlSession.commit()
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="userMapper">
<update id="save" parameterType="com.example.domain.User">
update user set username=#{username},password=#{password} where id=#{id}
update>
<insert id="save" parameterType="com.example.domain.User">
insert into user values(#{id},#{username},#{password})
insert>
<select id="findAll" resultType="com.example.domain.User">
select * from user
select>
mapper>
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
import java.util.List;
public class MyBatisTest {
@Test
public void test03() {
//模拟user对象
User user = new User();
user.setUsername("张三");
user.setPassword("123")
//获取核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获得session工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得session回话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行操作 参数:namespace+id
sqlSession.update("userMapper.update",user);
//mybatis默认事务不提交 要执行插入操作,就要提交数据
sqlSession.commit();
//打印数据
System.out.println(userList);
//释放资源
sqlSession.close();
}
}
sqlSession.update("命名空间.id",实体对象);
按id删除
<delete id="delete" parameterType="java.lang.Integer">
delete from user where id=#{id}
delete>
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
import java.util.List;
public class MyBatisTest {
@Test
public void test03() {
//获取核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获得session工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得session回话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行操作 参数:namespace+id
sqlSession.delete("userMapper.delete",7);
//mybatis默认事务不提交 要执行插入操作,就要提交数据
sqlSession.commit();
//打印数据
System.out.println(userList);
//释放资源
sqlSession.close();
}
}
sqlSession.delete("命名空间.id",Object);
数据库环境的配置,支持多环节配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HMvYtZkK-1632051628446)(C:\Users\Superclass\IdeaProjects\demo01\src\main\resources\SpingLearn\Mybatis配置.png)]
其中,事务管理器 transactionManager 类型有两种:
该标签的作用是加载映射,加载方式有:
sqlMapConfig.xml 可以通过properties 标签加载外部properties文件
自定义别名
<typeAliases>
<typeAlias type="com.example.domain.User" alias="user">typeAlias>
typeAliases>
常用API:SqlSessionFactory build(InputStream inputStream)
通过加载mybatis的核心文件的输入流形式构建一个SqlSessionfactory对象
String resource = "prg/mybatis/builder/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(inputStream);
SqlSessionFactory有多个方法创建SqlSession实例,常用:
方法 | 解释 |
---|---|
openSession() | 会默认开启一个事务,但事务不会自动提交,也就意味着需要手动提交该事务,更新操作数据才会持久化到数据库 |
openSession(boolean autoCommit) | 参数为是否自动提交,如果设置为true,那么不需要手动提交事务 |
<T> T selectOne(String statement, Object parameter)
<E> List<E> selectList(String statement, Object parameter)
int insert(String statement,Object parameter)
int update(String statement,Object parameter)
int delete(String statement,Object parameter)
操作事务的方法主要有:
void commit();
void rollback();
import java.io.IOException;
public interface UserDao {
List<User> findAll() throws IOException;
}
只需要编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法同上边Dao接口实现类方法
Mapper接口开发需要遵循一下规范:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BIgaSI7n-1632051628448)(C:\Users\Superclass\IdeaProjects\demo01\src\main\resources\SpingLearn\UserMapper.png)]
Dynamic SQL
MyBatis 最强大的特性之一就是它的动态语句功能。如果您以前有使用 JDBC 或者类似框架的经历,您就会明白把 SQL 语句条件连接在一起是多么的痛苦,要确保不能忘记空格或者不要在 columns 列后面省略一个逗号等。动态语句能够完全解决掉这些痛苦。
尽管与动态 SQL 一起工作不是在开一个 party,但是 MyBatis 确实能通过在任何映射 SQL 语句中使用强大的动态 SQL 来改进这些状况。
动态 SQL 元素对于任何使用过 JSTL 或者类似于 XML 之类的文本处理器的人来说,都是非常熟悉的。在上一版本中,需要了解和学习非常多的元素,但在 MyBatis3 中有了许多的改进,现在只剩下差不多二分之一的元素。MyBatis 使用了基于强大的 OGNL 表达式来消除了大部分元素。
- if
- choose(when,otherwise)
- trim(where,set)
- foreach
实现:
UserMapper.xml
<select id="findByCondition" parameterType="user" resultType="user">
select * from user
<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>
<select id="findByCondition" parameterType="user" resultType="user">
select * from user
<where>
<foreach collection="list" open="id in(" close=")" item="id" separator=",">
#{id}
foreach>
where>
select>
<sql id="selectUser">select * from usersql>
<select id="findByCondition" parameterType="user" resultType="user">
<include refid="selectUser">include>
<where>
<foreach collection="list" open="id in(" close=")" item="id" separator=",">
#{id}
foreach>
where>
select>
无论是Mybatis在预处理语句(PrepareStatement)中设置一个参数时,还是从结果集中取出一个值时,都会用类型处理器将获取的值以合适的方式转换成Java类型。
类型处理器 | Java类型 | JDBC类型 |
---|---|---|
BooleanTypeHandler |
java.lang.Boolean, boolean |
数据库兼容的BOOLEAN |
ByteTypeHandler |
java.lang.Byte,byte |
数据库兼容的NUMERIC 或BYTE |
ShortTypeHandler |
java.lang.Short,short |
数据库兼容的NUMERIC 或SHORT INTEGER |
IntegerTypeHandler |
java.lang.Integer,integer |
数据库兼容的NUMERIC 或INTEFER |
LongTypeHandler |
java.lang.Long,long |
数据库兼容的NUMERIC 或LONG INTEGER |
可以重写类型处理器或创建自己的类型处理器来处理不支持的或非标准的类型。具体做法为:实现org.apache.ibatis.type.TypeHandler接口,或继承一个很便利的类org.apache.ibatis.type.BaseTypeHandler,
然后可以选择性地将它映射到一个JDBC类型。例如需求:一个Java中的Data数据类型,我想将它存到数据库的时候存成一个1970至今的毫秒数,取出来的时候转换成java的Date,即java的Date与数据库中的varchar毫秒值之间的转换
开发步骤;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
public class DateTypeHandler extends BaseTypeHandler<Date> {
//java----->数据库
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date date, JdbcType jdbcType) throws SQLException {
long time = date.getTime();
preparedStatement.setLong(i, time);
}
//数据库中类型----->java
//String参数 要转换的字段名称
//ResultSet 查询出的结果集
@Override
public Date getNullableResult(ResultSet resultSet, String s) throws SQLException {
//获得结果集中需要的数据(long----->Date)
long aLong = resultSet.getLong(s);
Date date = new Date(aLong);
return date;
}
@Override
public Date getNullableResult(ResultSet resultSet, int i) throws SQLException {
long aLong = resultSet.getLong(s);
Date date = new Date(aLong);
return date;
return null;
}
@Override
public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
long aLong = callableStatement.getLong(i);
Date date = new Date(aLong);
return date;
}
}
<typeHandlers>
<typeHandler handler="com.example.handler.DateTypeHandler">typeHandler>
typeHandlers>
MyBatis可以使用第三方的插件来对功能进行扩展,分页助手PageHelper是将分页的复杂操作进行封装,使用简单的方式即可获得分页
开发步骤:
PageHelper获取分页
PageHelper.startPage(1,3)//设置分页相关参数 当前页+每页显示显示的条数
PageInfo
pageInfo.getPageNum();//当前页
pageInfo.getPageSize();//每页显示条数
pageInfo.getTotal();//总条数
pageInfo.getPages();//总页数
pageInfo.getPrePage();//上一页
pageInfo.getNextPage();//下一页
pageInfo.isFirstPage();//是否是第一页
public class User{
private int id;
private String username;
private String password;
}
import java.util.Date;
public class Order {
private int id;
private Date ordertime;
private double total;
private User user;
}
OrderMapper.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="user">
<id column="uid" property="id">id>
<result column="username" property="username">result>
<result column="password" property="password">result>
association>
resultMap>
<select id="findAll" resultMap="orderMap">
SELECT *,o.id oid FROM orders o,USER u WHERE o.uid =u.id
select>
public class User{
private int id;
private String username;
private String password;
private List<Order> orderList;
}
UserMapper.xml
<resultMap id="orderMap" type="order">
<id column="uid" property="id">id>
result>
<result column="username" property="username">result>
<result column="password" property="password">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="orderMap">
SELECT *,o.id oid FROM orders o,USER u WHERE o.uid =u.id
select>
public class Role{
private int id;
private String roleName;
private String roleDesc;
}
public class User{
private int id;
private String username;
private String password;
private List<Order> orderList;
private List<Role> roleList;
}
<resultMap id="userRoleMap" type="user">
<id column="userId" property="id">id>
result>
<result column="username" property="username">result>
<result column="password" property="password">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="findAll" resultMap="userRoleMap">
SELECT * FROM USER u,sys_user_role ur,sys_role r WHERE u.id=ur.userId AND ur.roleID=r.id
select>
注解 | 效果 |
---|---|
@Inseert | 新增 |
@Update | 更新 |
@Delete | 删除 |
@Select | 查询 |
@Result | 结果集封装 |
@Results | 可以与@Result一起使用,封装多个结果集 |
@One | 实现一对一结果集封装 |
@Many | 实现一对多结果集封装 |
import org.apache.ibatis.annotations.Insert;
public interface UserMapper {
@Insert("insert into user values(#{id},#{username},#{password}})")
public void save(User user);
@Update("update user set username=#{username},password=#{password} where id=#{id}")
public void update(User user);
@Delete("delete from user where id=#{id}")
public void delete(int id);
@Select("select * from user where id=#{id}")
public User findById(int id);
#Select("select * from user")
public List<User> findAll();
}
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before
import java.io.InputStream;
public class MyBatisTest {
private UserMapper mapper;
@Before
public void before() {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapCongig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
mapper = sqlSession.getMapper(UserMapper.class);
}
@Test
public void testSave(){
User user = new User();
user.setUserName("张三");
user.setPassword("222");
maper.save(user);
}
@Test
public void testUpdate(){
User user = new User();
user.setId(1);
user.setUserName("kkk");
user.setPassword("111");
mapper.update(user);
}
@Test
public void delete(){
mapper.delete(1);
}
}
import org.apache.ibatis.annotations.Result;
public interface OrderMapper {
@Select("select *,o.id oid from orders o,user u where o.uid=u.id")
@Result({
@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 = "user.username"),
@Result(column = "password" , property = "user.password"),
})
}
或者
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
public interface OrderMapper {
@Select("select *,o.id oid from orders o,user u where o.uid=u.id")
@Result({
@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属性,代表查询哪个接口的方法获得数据
one = @One(select = "com.example.mapper.UserMapper.findById")
)
})
}
一对多
import org.apache.ibatis.annotations.Select;
public interface OrderMapper{
@Select("select * from orders where uid=#{uid}")
public List<Order> findByUid(int uid);
}
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
public interface UserMapper {
@Select(select * from user)
@Results(
@Result(id = true, column = "id", property = "id"),
@Result(column = "username", property = "username"),
@Result(column = "password", property = "password"),
@Result(
property = "orderList",
column = "id",
javaType = List.class,
many = @Many(select = "com.example.mapper.OrderMapper.")
)
)
public List<User> findUserAndOrderAll();
}