MapperScannerConfigurer
是Spring与MyBatis集成时的一个关键组件,它用于自动扫描指定包下的Mapper接口并创建相应的代理对象。当你设置了<property name="basePackage" value="com.ssm.mapper">
,它会查找以com.ssm.mapper
开头的Java包中的Mapper接口。
然而,在你的配置中错误地使用了ref
属性而不是value
属性,应该是这样:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.ssm.mapper"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
这里的ref="sqlSessionFactory"
意味着sqlSessionFactory
bean应该已经在应用上下文中存在并且是可注入的。正确的配置确保了Spring能够识别Mapper接口,扫描它们并将它们与SqlSessionFactory连接起来,以便在业务逻辑中通过接口调用执行SQL。
MapperScannerConfigurer
是 Spring Boot 中用于扫描和自动装配 MyBatis 映射器(Mapper)接口的一个工具类。它能够帮助管理 MyBatis 的全局配置,比如数据源(DataSource)、SqlSessionFactory 和 Mapper
接口的扫描范围。
当你在 Spring 容器中使用 @MapperScan
注解时,MapperScannerConfigurer
会自动检测是否有重复的 Mapper
接口定义。如果发现有两个或更多的 Mapper
类具有相同的完全限定名(即包名+类名),它会抛出错误,提示 “Bean already defined with the same name!”,这是为了避免在单个应用上下文中配置重复的 Mapper
。
为了避免这种重复,你应该确保每个 @MapperScan
注解指向不同的包,或者在其他配置中只使用一次 MapperScannerConfigurer
。如果你使用了 MyBatis Plus,可能会因为其自身的配置导致冲突,这时可以考虑去掉其中不必要的 @MapperScan
,让 Spring 自动扫描默认的包。
相关问题–:
-
如何在Spring Boot中手动配置MapperScannerConfigurer?
-
如果我想使用多个MapperScannerConfigurer,应该如何操作以防止冲突?
-
我如何知道哪个包应该在
@MapperScan
中指定?
MapperScannerConfigurer
是Spring与MyBatis集成过程中的一个重要工具,其主要作用是简化Mapper接口的管理。当配置这个组件时,你需要做以下几个步骤: -
配置扫描范围: 在Spring配置文件中设置
MapperScannerConfigurer
,指定要扫描的包路径。这使得MyBatis能够自动找到该包内的Mapper接口。<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.example.mapper" /> </bean>
-
自动代理生成: 当
MapperScannerConfigurer
扫描到Mapper接口时,它会动态地创建这些接口的代理实例。这是因为MyBatis的Mapper接口通常不直接暴露给Spring,而是通过代理机制来保证AOP(面向切面编程)的执行。 -
注入到Spring容器: 创建的代理对象会被Spring管理,并注入到需要的地方,如DAO层的Service中,方便后续调用Mapper的方法。
-
过滤选项: 如果需要,可以通过
annotationClass
属性指定特定的注解(如@Mapper),或使用markerInterface
属性来限制扫描的接口类型。<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="annotationClass" value="com.example.annotation.MyMapper" /> <property name="markerInterface" value="com.example.base.BaseMapper" /> </bean>
这样,无需手动为每个Mapper接口创建MapperFactoryBean
,Spring会自动完成这个过程,提高了开发效率。
MapperScannerConfigurer
避免扫描非Mapper接口的关键在于它只识别那些声明为接口的映射器。当配置这个Bean时,通过设置basePackage
属性来指定要扫描的包名。basePackage
通常包含了应用中所有Mapper接口定义的地方。
例如,在XML配置中,如引用[5]所示:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="org.mybatis.spring.sample.mapper" />
</bean>
这里的basePackage
指定了org.mybatis.spring.sample.mapper
下的所有包及其子包,Spring会自动查找这些包下声明为Mapper
接口的类,并创建对应的代理实例注入到Spring容器中。由于接口的代理是在运行时动态生成的,所以只有接口类型的映射器才会被扫描和代理,而非具体实现类不会被错误地包括进来。
如果一个类实现了Mapper
接口但不采用Mapper
作为类名,按照MyBatis的默认扫描策略,它可能不会被自动扫描到。MyBatis通常是基于接口名称来查找与之相应的XML映射文件的,即期望接口名为UserMapper
时,会去寻找UserMapper.xml
文件。如果你的类命名为其他形式,比如CustomMapper
,尽管它实现了Mapper
接口,但由于名字不符合约定,mybatis可能会找不到对应的XML配置。
为了确保能被扫描,你需要按照以下一种或多种方式配置:
-
使用
<package>
标签,指定接口所在的包名,这样MyBatis会在该包及其子包下搜索接口及其对应XML:<mappers> <package name="your.package.name"/> </mappers>
-
明确指定每个
<mapper>
元素的class
属性,即使类名非标准:<mappers> <mapper class="com.your.package.CustomMapper"/> </mappers>
然而,推荐的做法还是保持接口和XML文件的名称匹配,以便更直观地管理配置。
- Mybatis MapperScannerConfigurer 自动扫描
将Mapper接口生成代理注入到SpringMybatis在与Spring集成的时候可以配置MapperFactoryBean来生成Mapper接口的代理。
package com.ssm.chapter15.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttribute;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
import com.ssm.chapter15.pojo.Role;
import com.ssm.chapter15.service.RoleService;
@Controller
@RequestMapping("/attribute")
//可以配置数据模型的名称和类型,两者取或关系
@SessionAttributes(names ={
"id"}, types = {
Role.class })
public class AttributeController {
@Autowired
private RoleService roleService = null;
@RequestMapping("/requestAttribute")
public ModelAndView reqAttr(@RequestAttribute("id") Long id) {
ModelAndView mv = new ModelAndView();
Role role = roleService.getRole(id);
mv.addObject("role", role);
mv.setView(new MappingJackson2JsonView());
return mv;
}
@RequestMapping("/sessionAttributes")
public ModelAndView sessionAttrs(Long id) {
ModelAndView mv = new ModelAndView();
Role role = roleService.getRole(id);
//根据类型,session将会保存角色信息
mv.addObject("role", role);
//根据名称,session将会保存id
mv.addObject("id", id);
//视图名称,定义跳转到一个JSP文件上
mv.setViewName("sessionAttribute");
return mv;
}
@RequestMapping("/sessionAttribute")
public ModelAndView sessionAttr(@SessionAttribute("id") Long id) {
ModelAndView mv = new ModelAndView();
Role role = roleService.getRole(id);
mv.addObject("role", role);
mv.setView(new MappingJackson2JsonView());
return mv;
}
@RequestMapping("/getHeaderAndCookie")
public String testHeaderAndCookie(
@RequestHeader(value="User-Agent", required = false, defaultValue = "attribute")
String userAgent,
@CookieValue(value = "JSESSIONID", required = true, defaultValue = "MyJsessionId")
String jsessionId) {
System.out.println("User-Agent:" + userAgent);
System.out.println("JSESSIONID:" + jsessionId);
return "index";
}
}
package com.ssm.chapter15.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
import com.ssm.chapter15.pojo.Role;
import com.ssm.chapter15.pojo.RoleParams;
import com.ssm.chapter15.service.RoleService;
@Controller
@RequestMapping("/params")
public class ParamsController {
@RequestMapping("/commonParams")
public ModelAndView commonParams(String roleName, String note) {
System.out.println("roleName =>" + roleName);
System.out.println("note =>" + note);
ModelAndView mv = new ModelAndView();
mv.setViewName("index");
return mv;
}
@RequestMapping("/commonParamPojo")
public ModelAndView commonParamPojo(RoleParams roleParams) {
System.out.println("roleName =>" + roleParams.getRoleName());
System.out.println("note =>" + roleParams.getNote());
ModelAndView mv = new ModelAndView();
mv.setViewName("index");
return mv;
}
@RequestMapping("/requestParam")
//使用@RequestParam("role_name")指定映射HTTP参数名称
public ModelAndView requestParam(@RequestParam("role_name") String roleName, String note) {
System.out.println("roleName =>" + roleName);
System.out.println("note =>" + note);
ModelAndView mv = new ModelAndView();
mv.setViewName("index");
return mv;
}
//注入角色服务对象
@Autowired
RoleService roleService;
//{id}代表接收一个参数
@RequestMapping("/getRole/{id}")
//注解@PathVariable表示从URL的请求地址中获取参数
public ModelAndView pathVariable(@PathVariable("id") Long id) {
Role role = roleService.getRole(id);
ModelAndView mv = new ModelAndView();
//绑定数据模型
mv.addObject(role);
//设置为JSON视图
mv.setView(new MappingJackson2JsonView());
return mv;
}
@RequestMapping("/findRoles")
public ModelAndView findRoles(@RequestBody RoleParams roleParams) {
List<Role> roleList = roleService.findRoles(roleParams);
ModelAndView mv = new ModelAndView();
//绑定模型
mv.addObject(roleList);
//设置为JSON视图
mv.setView(new MappingJackson2JsonView());
return mv;
}
@RequestMapping("/deleteRoles")
public ModelAndView deleteRoles(@RequestBody List<Long> idList) {
ModelAndView mv = new ModelAndView();
//删除角色
int total = roleService.deleteRoles(idList);
//绑定视图
mv.addObject("total", total);
//JSON视图
mv.setView(new MappingJackson2JsonView());
return mv;
}
@RequestMapping("/addRoles")
public ModelAndView addRoles(@RequestBody List<Role> roleList) {
ModelAndView mv = new ModelAndView();
//删除角色
int total = roleService.insertRoles(roleList);
//绑定视图
mv.addObject("total", total);
//JSON视图
mv.setView(new MappingJackson2JsonView());
return mv;
}
@RequestMapping("/commonParamPojo2")
public ModelAndView commonParamPojo2(String roleName, String note) {
System.out.println("roleName =>" + roleName);
System.out.println("note =>" + note);
ModelAndView mv = new ModelAndView();
mv.setViewName("index");
return mv;
}
}
package com.ssm.chapter15.controller;
import java.util.List;
import java.util.Map;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
import com.ssm.chapter15.pojo.PageParams;
import com.ssm.chapter15.pojo.Role;
import com.ssm.chapter15.pojo.RoleParams;
import com.ssm.chapter15.service.RoleService;
import com.ssm.chapter15.view.ExcelExportService;
import com.ssm.chapter15.view.ExcelView;
@Controller
@RequestMapping("/role")
public class RoleController {
@Autowired
private RoleService roleService = null;
@RequestMapping("/showRoleJsonInfo")
public Model