背景:
最近项目中涉及到要实现继承对象的获取,由于习惯用注解实现mybatis对象映射,所以也想用@TypeDiscriminator实现。但是在百度中却搜索不到@TypeDiscriminator的应用实例,幸好能上国外网,Google之。下面以一个最简单的例子来讲@TypeDiscriminator用法。
例子:
有五个对象,Person,Teacher,Student,Answer,Scholarship,Teacher和Student继承于Person,Teacher扩展answers属性,Student扩展scholarship属性。
// ------------------------------------------------------------------------
package org.zyd.java.springboot.test.mybatis.person;
public class Person {
protected Integer id;
protected String type;
protected String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// ------------------------------------------------------------------------
package org.zyd.java.springboot.test.mybatis.person;
import java.util.List;
import org.apache.ibatis.annotations.*;
import org.zyd.java.springboot.test.mybatis.person.student.Student;
import org.zyd.java.springboot.test.mybatis.person.teacher.Teacher;
@Mapper
public interface PersonRepository {
@Insert("insert into person (name) values (#{name})")
int insert(Person person);
@Delete("delete from person where id = #{id}")
int delete(@Param("id") Integer id);
@Update("update person set name=IFNULL(#{name}, name) where id = #{id}")
int update(Person person);
@Select("select * from person")
@TypeDiscriminator(javaType = String.class, column = "type", cases = {
@Case(value = "teacher", type = Teacher.class, results = { @Result(property = "id", column = "id"),
@Result(property = "answers", column = "id", many = @Many(select = "org.zyd.java.springboot.test.mybatis.answer.AnswerRepository.searchByPerson")) }),
@Case(value = "student", type = Student.class, results = { @Result(property = "id", column = "id"),
@Result(property = "scholarship", column = "id", one = @One(select = "org.zyd.java.springboot.test.mybatis.scholarship.ScholarshipRepository.searchByPerson"), javaType = Student.class) }) })
List<Person> search();
}
// ------------------------------------------------------------------------
package org.zyd.java.springboot.test.mybatis.person;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class PersonService {
@Autowired
PersonRepository personRepository;
int insert(Person person) {
return personRepository.insert(person);
}
int delete(Integer id) {
return personRepository.delete(id);
}
int update(Person person) {
return personRepository.update(person);
}
List<Person> search() {
return personRepository.search();
}
}
// ------------------------------------------------------------------------
package org.zyd.java.springboot.test.mybatis.person;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
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.bind.annotation.RestController;
@RestController
@RequestMapping(path = "/person")
public class PersonController {
@Autowired
PersonService personService;
@PostMapping("insert")
public int insert(@RequestBody Person person) {
return personService.insert(person);
}
@PostMapping("delete")
public int delete(@RequestParam("id") Integer id) {
return personService.delete(id);
}
@PostMapping("update")
public int update(@RequestBody Person person) {
return personService.update(person);
}
@GetMapping("search")
public List<Person> search() {
return personService.search();
}
}
// ------------------------------------------------------------------------
package org.zyd.java.springboot.test.mybatis.person.teacher;
import java.util.List;
import org.zyd.java.springboot.test.mybatis.answer.Answer;
import org.zyd.java.springboot.test.mybatis.person.Person;
public class Teacher extends Person {
private List<Answer> answers;
public List<Answer> getAnswers() {
return answers;
}
public void setAnswers(List<Answer> answers) {
this.answers = answers;
}
}
// ------------------------------------------------------------------------
package org.zyd.java.springboot.test.mybatis.person.student;
import org.zyd.java.springboot.test.mybatis.person.Person;
import org.zyd.java.springboot.test.mybatis.scholarship.Scholarship;
public class Student extends Person {
private Scholarship scholarship;
public Scholarship getScholarship() {
return scholarship;
}
public void setScholarship(Scholarship scholarship) {
this.scholarship = scholarship;
}
}
// ------------------------------------------------------------------------
package org.zyd.java.springboot.test.mybatis.answer;
public class Answer {
private Integer id;
private String subject;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
}
// ------------------------------------------------------------------------
package org.zyd.java.springboot.test.mybatis.answer;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface AnswerRepository {
@Select("select * from answer where person_id=#{personId}")
List<Answer> searchByPerson(@Param("personId") Integer personId);
}
// ------------------------------------------------------------------------
package org.zyd.java.springboot.test.mybatis.scholarship;
public class Scholarship {
private Integer id;
private Integer level;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getLevel() {
return level;
}
public void setLevel(Integer level) {
this.level = level;
}
}
// ------------------------------------------------------------------------
package org.zyd.java.springboot.test.mybatis.scholarship;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface ScholarshipRepository {
@Select("select * from scholarship where person_id=#{personId}")
Scholarship searchByPerson(@Param("personId") Integer personId);
}
在实现过程中,填了两个坑:
1. 需指明Student类型
javaType = Student.class
否则会报错:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: Could not set property 'scholarship' of 'class org.zyd.java.springboot.test.mybatis.person.student.Student' with value 'org.zyd.java.springboot.test.mybatis.scholarship.Scholarship@6b616750' Cause: java.lang.IllegalArgumentException: argument type mismatch] with root cause
这个坑非常坑,纠结了很久,最开始我在数据库里有两条person数据,一个为teacher,一个为student,我发现List<Answer>并没有报错,但是Scholarship却不能映射,以为只能映射基本java类型,但是想想之前关联查询也有可以映射,说明并不是不能映射,而是mybatis在此时并不认识Student类型,所以解决之。
2. 需手动映射id
@Result(property = "id", column = "id"),
不然查出来的Teacher和Student的id都会为null。
现在,查询实现了,但是调用接口的时候,比如插入一个Person(有可能是Teacher,或者Student),怎么去统一接口调用呢?即实现post路径都是 localhost:8080/person/insert。惯例,google之。实现中使用了一些java映射的trick:获取到相应的子类service,同时转化实例为子类对象,还是有点意思的,实现源代码就不再贴一遍了,直接下载吧:
https://download.csdn.net/download/chunzhenzyd/10835621 (如果链接不对的话,可以去我的资源列表去找)
在实现过程中,填了一个坑:
1. 需指定visible=true
不然得不到Person中的属性值,比如getType会返回null。