美文网首页springjava
springboot-整合mybatis,security

springboot-整合mybatis,security

作者: 谁在烽烟彼岸 | 来源:发表于2017-09-04 17:38 被阅读325次

    最近做项目用到springboot整合mybatis,security。将其中遇到的问题做一个总结

    注:本项目全程无xml文件,使用注解来添加配置。

    注:本项目使用Gradle进行构建。

    build.gradle

    buildscript {

    ext {

    springBootVersion ='1.5.6.RELEASE'

       }

    repositories {

    mavenCentral()

        }

    dependencies {

    classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")

          }

      }

    applyplugin:'java'

    applyplugin:'eclipse-wtp'

    applyplugin:'org.springframework.boot'

    applyplugin:'war'

    version='0.0.1-SNAPSHOT'

    sourceCompatibility =1.8

    repositories {

    mavenCentral()

         }

    configurations {

    providedRuntime

       }

    dependencies {

    compile('org.springframework.boot:spring-boot-starter-data-redis')

    compile('org.springframework.boot:spring-boot-starter-freemarker')

    compile('org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.1')

    compile('org.springframework.boot:spring-boot-starter-security')

    compile('org.springframework.boot:spring-boot-starter-thymeleaf')

    compile('org.springframework.boot:spring-boot-starter-actuator')

    compilegroup:'org.springframework.boot',name:'spring-boot-starter-mobile',version:'1.5.4.RELEASE'

    compile("org.springframework.boot:spring-boot-devtools")

    compile('org.apache.commons:commons-io:1.3.2')

    compilegroup:'io.jsonwebtoken',name:'jjwt',version:'0.7.0'

    compilegroup:'org.apache.commons',name:'commons-lang3',version:'3.6'

    compilegroup:'commons-beanutils',name:'commons-beanutils',version:'1.9.3'

    compilegroup:'org.apache.poi',name:'poi',version:'3.10.1'

    compileOnly"org.projectlombok:lombok:1.16.16"

    runtime('mysql:mysql-connector-java')

    providedRuntime('org.springframework.boot:spring-boot-starter-tomcat')

    testCompile('org.springframework.boot:spring-boot-starter-test')

    testCompile('org.springframework.security:spring-security-test')

    }

    本项目使用JWT实现security验证

    application.yml如下

    server:

         port:8080

         session:

                timeout:1800

         max-http-header-size:20971520

    spring:

          jackson:

                date-format:yyyy-MM-dd HH:mm:ss

                 time-zone:GMT+8

          datasource:

                 url:jdbc:mysql://127.0.0.1:3306/captable

                 username:dev

                 password:GoAhead-1985

                 driver-class-name:com.mysql.jdbc.Driver

    jwt:

           header:Authorization

            secret:mySecret

            expiration:604800

            route:

                  authentication:

                          path:auth

                          refresh:refresh

    那么肉戏来了:怎么使用无xml实现mybatis

    springboot已经整合mybatis,我们不用自己整合mybatis,只需编写Mapper了就好;

    在interface  Mapper中使用注解

    l 映射语句

    @Insert,@Update,@Delete,@SeelctStatements

    l 结果映射

               一对一映射

              一对多映射

    l 动态SQL

             @SelectProvider

              @InsertProvider

             @UpdateProvider

              @DeleteProvider

     映射语句

    MyBatis提供了多种注解来支持不同类型的语句(statement)如SELECT,INSERT,UPDATE,DELETE。让我们看一下具体怎样配置映射语句。

     1.@Insert

    我们可以使用@Insert注解来定义一个INSERT映射语句:

    [java]

    packagecom.mybatis3.mappers;

    public interface StudentMapper

    {

    @Insert("INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL,ADDR_ID, PHONE)

    VALUES(#{studId},#{name},#{email},#{address.addrId},#{phone})")

    int insertStudent(Student student);

    }

    使用了@Insert注解的insertMethod()方法将返回insert语句执行后影响的行数

    自动生成主键

    在上一章中我们讨论过主键列值可以自动生成。我们可以使用@Options注解的userGeneratedKeys 和keyProperty属性让数据库产生auto_increment(自增长)列的值,然后将生成的值设置到输入参数对象的属性中。

    [java]

    @Insert("INSERT INTO STUDENTS(NAME,EMAIL,ADDR_ID, PHONE)

    VALUES(#{name},#{email},#{address.addrId},#{phone})")

    @Options(useGeneratedKeys =true, keyProperty ="studId")

    int insertStudent(Student student);

    这里STUD_ID列值将会通过MySQL数据库自动生成。并且生成的值将会被设置到student对象的studId属性中。

    [java]

    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

    mapper.insertStudent(student);

    int studentId = student.getStudId();

    有一些数据库如Orcal,并不支持AUTO_INCREMENT列属性,它使用序列(SEQUENCE)来产生主键的值。

    我们可以使用@SelectKey注解来为任意SQL语句来指定主键值,作为主键列的值。

    假设我们有一个名为STUD_ID_SEQ的序列来生成STUD_ID主键值。

    该项目使用mysql数据库,所以在该处使用的是uuid()函数.

    [java]

    @Insert("INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL,ADDR_ID, PHONE)

    VALUES(#{studId},#{name},#{email},#{address.addrId},#{phone})")

    @SelectKey(statement="SELECT STUD_ID_SEQ.NEXTVAL FROM DUAL",

    keyProperty="studId", resultType=int.class, before=true)

    int insertStudent(Student student);

    这里我们使用了@SelectKey来生成主键值,并且存储到了student对象的studId属性上。由于我们设置了before=true,该语句将会在执行INSERT语句之前执行。

    如果你使用序列作为触发器来设置主键值,我们可以在INSERT语句执行后,从sequence_name.currval获取数据库产生的主键值。

    [java]

    @Insert("INSERT INTO STUDENTS(NAME,EMAIL,ADDR_ID, PHONE)

    VALUES(#{name},#{email},#{address.addrId},#{phone})")

    @SelectKey(statement="SELECT STUD_ID_SEQ.CURRVAL FROM DUAL",

    keyProperty="studId", resultType=int.class, before=false)

    intinsertStudent(Student student);

    2.@Update

    我们可以使用@Update注解来定义一个UPDATE映射语句,如下所示:

    [java]

    @Update("UPDATE STUDENTS SET NAME=#{name}, EMAIL=#{email},

    PHONE=#{phone} WHERE STUD_ID=#{studId}")

    int updateStudent(Student student);

    使用了@Update的updateStudent()方法将会返回执行了update语句后影响的行数。

    [java]

    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

    int noOfRowsUpdated = mapper.updateStudent(student);

    3.@Delete

    我们可以使用@Delete  注解来定义一个DELETE映射语句,如下所示:

    [java]

    @Delete("DELETE FROM STUDENTS WHERE STUD_ID=#{studId}")

    int deleteStudent(int studId);

    使用了@Delete的deleteStudent()方法将会返回执行了update语句后影响的行数。

    4.@Select

    我们可以使用@ Select注解来定义一个SELECT映射语句。

    让我们看一下怎样使用注解配置一个简单的select查询。

    [java]

    packagecom.mybatis3.mappers;

    publicinterfaceStudentMapper

    {

    @Select("SELECT STUD_ID AS STUDID, NAME, EMAIL, PHONE FROM

    STUDENTS WHERE STUD_ID=#{studId}")

    Student findStudentById(Integer studId);

    }

    为了将列名和Studentbean属性名匹配,我们为stud_id起了一个studId的别名。如果返回了多行结果,将抛出 TooManyResultsException异常。

    结果映射

    我们可以将查询结果通过别名或者是@Results注解与JavaBean属性映射起来。

    现在让我们看看怎样使用@Results注解将指定列于指定JavaBean属性映射器来,执行SELECT查询的:

    [java]

    packagecom.mybatis3.mappers;

    public interface StudentMapper

    {

    @Select("SELECT * FROM STUDENTS")

    @Results(

    {

    @Result(id =true, column ="stud_id", property ="studId"),

    @Result(column ="name", property ="name"),

    @Result(column ="email", property ="email"),

    @Result(column ="addr_id", property ="address.addrId")

    })

    List findAllStudents();

    }

    例如,看下面的findStudentById()和findAllStudents()方法:

    [java]

    @Select("SELECT * FROM STUDENTS WHERE STUD_ID=#{studId}")

    @Results(

    {

    @Result(id =true, column ="stud_id", property ="studId"),

    @Result(column ="name", property ="name"),

    @Result(column ="email", property ="email"),

    @Result(column ="addr_id", property ="address.addrId")

         })

    Student findStudentById(int studId);

    @Select("SELECT * FROM STUDENTS")

    @Results(

    {

    @Result(id =true, column ="stud_id", property ="studId"),

    @Result(column ="name", property ="name"),

    @Result(column ="email", property ="email"),

    @Result(column ="addr_id", property ="address.addrId")

            })

    List findAllStudents();

    这里两个语句的@Results配置完全相同,但是我必须得重复它。这里有一个解决方法。我们可以创建一个映射器Mapper配置文件, 然后配置元素,然后使用@ResultMap注解引用此。

    在StudentMapper.xml中定义一个ID为StudentResult的。

    在StudentMapper.java中,使用@ResultMap引用名为StudentResult的resultMap。

    [java]

    public interface StudentMapper

    {

    @Select("SELECT * FROM STUDENTS WHERE STUD_ID=#{studId}")

    @ResultMap("com.mybatis3.mappers.StudentMapper.StudentResult")

    Student findStudentById(intstudId);

    @Select("SELECT * FROM STUDENTS")

    @ResultMap("com.mybatis3.mappers.StudentMapper.StudentResult")

    List findAllStudents();

     }

    1 一对一映射

    MyBatis提供了@One注解来使用嵌套select语句(Nested-Select)加载一对一关联查询数据。让我们看看怎样使用@One注解获取学生及其地址信息。

    [java]

    public interface StudentMapper

    {

    @Select("SELECT ADDR_ID AS ADDRID, STREET, CITY, STATE, ZIP, COUNTRY

    FROM ADDRESSES WHERE ADDR_ID=#{id}")

    Address findAddressById(intid);

    @Select("SELECT * FROM STUDENTS WHERE STUD_ID=#{studId} ")

    @Results(

    {

    @Result(id =true, column ="stud_id", property ="studId"),

    @Result(column ="name", property ="name"),

    @Result(column ="email", property ="email"),

    @Result(property ="address", column ="addr_id",

    one =@One(select = "com.mybatis3.mappers.StudentMapper.

    findAddressById"))

      })

    Student selectStudentWithAddress(intstudId);

    }

    这里我们使用了@One注解的select属性来指定一个使用了完全限定名的方法上,该方法会返回一个Address对象。使用column=”addr_id”,则STUEDNTS表中列addr_id的值将会作为输入参数传递给findAddressById()方法。如果@OneSELECT查询返回了多行结果,则会抛出TooManyResultsException异常。

    [java]

    intstudId =1;

    StudentMapper studentMapper =

    sqlSession.getMapper(StudentMapper.class);

    Student student = studentMapper.selectStudentWithAddress(studId);

    System.out.println("Student :"+student);

    System.out.println("Address :"+student.getAddress());

    我们可以通过基于XML的映射器配置,使用嵌套结果ResultMap来加载一对一关联的查询。而MyBatis3.2.2版本,并没有对应的注解支持。但是我们可以在映射器Mapper配置文件中配置并且使用@ResultMap注解来引用它。

    在StudentMapper.xml中配置,如下所示:

    [java]

    public interface StudentMapper

    {

    @Select("select stud_id, name, email, a.addr_id, street, city, state, zip, country" + "FROM students s left outer join addresses a

    on s.addr_id=a.addr_id" + "where stud_id=#{studId} ")

    @ResultMap("com.mybatis3.mappers.StudentMapper.

    StudentWithAddressResult")

    Student selectStudentWithAddress(intid);

    }

    2 一对多映射

    MyBatis提供了@Many注解,用来使用嵌套Select语句加载一对多关联查询。

    现在让我们看一下如何使用@Many注解获取一个讲师及其教授课程列表信息:

    [java]

    public interface TutorMapper

    {

    @Select("select addr_id as addrId, street, city, state, zip,

    country from addresses where addr_id=#{id}")

    Address findAddressById(int id);

    @Select("select * from courses where tutor_id=#{tutorId}")

    @Results(

    {

    @Result(id =true, column ="course_id", property ="courseId"),

    @Result(column ="name", property ="name"),

    @Result(column ="description", property ="description"),

    @Result(column ="start_date"property ="startDate"),

    @Result(column ="end_date"property ="endDate")

        })

    List findCoursesByTutorId(int tutorId);

    @Select("SELECT tutor_id, name as tutor_name, email, addr_id

    FROM tutors where tutor_id=#{tutorId}")

    @Results(

    {

    @Result(id =true, column ="tutor_id", property ="tutorId"),

    @Result(column ="tutor_name", property ="name"),

    @Result(column ="email", property ="email"),

    @Result(property ="address", column ="addr_id",

    one =@One(select = " com.mybatis3.

    mappers.TutorMapper.findAddressById")),

    @Result(property ="courses", column ="tutor_id",

    many =@Many(select = "com.mybatis3.mappers.TutorMapper.

    findCoursesByTutorId"))

       })

    Tutor findTutorById(inttutorId);

    }

    这里我们使用了@Many注解的select属性来指向一个完全限定名称的方法,该方法将返回一个List对象。使用column=”tutor_id”,TUTORS表中的tutor_id列值将会作为输入参数传递给findCoursesByTutorId()方法。

    我们可以通过基于XML的映射器配置,使用嵌套结果ResultMap来加载一对多关联的查询。而MyBatis3.2.2版本,并没有对应的注解支持。但是我们可以在映射器Mapper配置文件中配置并且使用@ResultMap注解来引用它。

    在TutorMapper.xml中配置,如下所示:

    [java]

    public interface TutorMapper

    {

    @Select("SELECT T.TUTOR_ID, T.NAME AS TUTOR_NAME, EMAIL,

    A.ADDR_ID, STREET, CITY, STATE, ZIP, COUNTRY, COURSE_ID, C.NAME,

    DESCRIPTION, START_DATE, END_DATE  FROM TUTORS T LEFT OUTER

    JOIN ADDRESSES A ON T.ADDR_ID=A.ADDR_ID LEFT OUTER JOIN COURSES

    C ON T.TUTOR_ID=C.TUTOR_ID WHERE T.TUTOR_ID=#{tutorId}")

    @ResultMap("com.mybatis3.mappers.TutorMapper.TutorResult")

    Tutor selectTutorById(int tutorId);

    }

    动态SQL

    有时候我们需要根据输入条件动态地构建SQL语句。MyBatis提供了各种注解如@InsertProvider,@UpdateProvider,@DeleteProvider和@SelectProvider,来帮助构建动态SQL语句,然后让MyBatis执行这些SQL语句。

    1 @SelectProvider

    现在让我们来看一个使用@SelectProvider注解来创建一个简单的SELECT映射语句的例子。

    创建一个TutorDynaSqlProvider.java类,以及findTutorByIdSql()方法,如下所示:

    [java]

    packagecom.mybatis3.sqlproviders;

    importorg.apache.ibatis.jdbc.SQL;

    publicclassTutorDynaSqlProvider

    {

    publicString findTutorByIdSql(inttutorId)

    {

    return"SELECT TUTOR_ID AS tutorId, NAME, EMAIL FROM TUTORS

    WHERE TUTOR_ID=" + tutorId;

      }

    }

    在TutorMapper.java接口中创建一个映射语句,如下:

    [java]

    @SelectProvider(type=TutorDynaSqlProvider.class, method="findTutorByIdSql")

    Tutor findTutorById(int tutorId);

    这里我们使用了@SelectProvider来指定了一个类,及其内部的方法,用来提供需要执行的SQL语句。

    但是使用字符串拼接的方法构建SQL语句是非常困难的,并且容易出错。所以MyBaits提供了一个SQL工具类不使用字符串拼接的方式,简化构造动态SQL语句。

    现在,让我们看看如何使用org.apache.ibatis.jdbc.SQL工具类来准备相同的SQL语句。

    [java] 

    packagecom.mybatis3.sqlproviders;

    import org.apache.ibatis.jdbc.SQL;

    public class TutorDynaSqlProvider

    {

    publicString findTutorByIdSql(final int tutorId)

    {

    return new SQL(){

    {

    SELECT("tutor_id as tutorId, name, email");

    FROM("tutors");

    WHERE("tutor_id="+ tutorId);

        } } .toString();

     }

    }

    SQL工具类会处理以合适的空格前缀和后缀来构造SQL语句。

    动态SQL provider方法可以接收以下其中一种参数:

    1.无参数

    2.映射器Mapper接口的方法同类型的参数

    3. java.util.Map

    如果SQL语句的准备不取决于输入参数,你可以使用不带参数的SQL Provider方法。

    例如:

    [java]

    publicString findTutorByIdSql()

    {

    returnnewSQL()

    {

    {

    SELECT("tutor_id as tutorId, name, email");

    FROM("tutors");

    WHERE("tutor_id = #{tutorId}");

       }

      } .toString();

    }

    这里我们没有使用输入参数构造SQL语句,所以它可以是一个无参方法。

    如果映射器Mapper接口方法只有一个参数,那么可以定义SQLProvider方法,它接受一个与Mapper接口方法相同类型的参数。

    例如映射器Mapper接口有如下定义:

    [java]

    Tutor findTutorById(int tutorId);

    这里findTutorById(int)方法只有一个int类型的参数。我们可以定义findTutorByIdSql(int)方法作为SQL provider方法。

    [java]

    publicString findTutorByIdSql(final int tutorId)

    {

    returnnewSQL()

    {

    {

    SELECT("tutor_id as tutorId, name, email");

    FROM("tutors");

    WHERE("tutor_id="+ tutorId);

       }

       } .toString();

    }

    如果映射器Mapper接口有多个输入参数,我们可以使用参数类型为java.util.Map的方法作为SQLprovider方法。然后映射器Mapper接口方法所有的输入参数将会被放到map中,以param1,param2等等作为key,将输入参数按序作为value。你也可以使用0,1,2等作为key值来取的输入参数。

    [java]

    @SelectProvider(type = TutorDynaSqlProvider.class,

    method ="findTutorByNameAndEmailSql")

    Tutor findTutorByNameAndEmail(String name, String email);

    publicString findTutorByNameAndEmailSql(Map map)

    {

    String name = (String) map.get("param1");

    String email = (String) map.get("param2");

    //you can also get those values using 0,1 keys

    //String name = (String) map.get("0");

    //String email = (String) map.get("1");

    returnnewSQL()

    {

    {

    SELECT("tutor_id as tutorId, name, email");

    FROM("tutors");

    WHERE("name=#{name} AND email=#{email}");

      }

       } .toString();

    }

    SQL工具类也提供了其他的方法来表示JOINS,ORDER_BY,GROUP_BY等等。

    让我们看一个使用LEFT_OUTER_JOIN的例子:

    [java]

    public class TutorDynaSqlProvider

    {

    public String selectTutorById()

    {

    returnnewSQL()

    {

    {

    SELECT("t.tutor_id, t.name as tutor_name, email");

    SELECT("a.addr_id, street, city, state, zip, country");

    SELECT("course_id, c.name as course_name, description,

    start_date, end_date");

    FROM("TUTORS t");

    LEFT_OUTER_JOIN("addresses a on t.addr_id=a.addr_id");

    LEFT_OUTER_JOIN("courses c on t.tutor_id=c.tutor_id");

    WHERE("t.TUTOR_ID = #{id}");

        }

        } .toString();

         }

       }

    public interface TutorMapper

    {

    @SelectProvider(type = TutorDynaSqlProvider.class,

    method ="selectTutorById")

    @ResultMap("com.mybatis3.mappers.TutorMapper.TutorResult")

    Tutor selectTutorById(int tutorId);

    }

    由于没有支持使用内嵌结果ResultMap的一对多关联映射的注解支持,我们可以使用基于XML的配置,然后与@ResultMap映射。

    使用了动态的SQL provider,我们可以取得讲师及其地址和课程明细。

     2 @InsertProvider

    我们可以使用@InsertProvider注解创建动态的INSERT语句,如下所示:

    [java]

    public class TutorDynaSqlProvider

    {

    public String  insertTutor(finalTutor tutor)

    {

    return new SQL()

    {

    {

    INSERT_INTO("TUTORS");

    if(tutor.getName() !=null)

    {

    VALUES("NAME","#{name}");

         }

    if(tutor.getEmail() !=null)

    {

    VALUES("EMAIL","#{email}");

       }

       }

       } .toString();

        }

        }

    public interface TutorMapper

    {

    @InsertProvider(type = TutorDynaSqlProvider.class,

    method ="insertTutor")

    @Options(useGeneratedKeys =true, keyProperty ="tutorId")

    int insertTutor(Tutor tutor);

    }

     3 @UpdateProvider

    我们可以通过@UpdateProvider注解创建UPDATE语句,如下所示:

    [java]

    publicclassTutorDynaSqlProvider

    {

    publicString updateTutor(finalTutor tutor)

    {

    returnnewSQL()

    {

    {

    UPDATE("TUTORS");

    if(tutor.getName() !=null)

    {

    SET("NAME = #{name}");

       }

    if(tutor.getEmail() !=null)

    {

    SET("EMAIL = #{email}");

       }

    WHERE("TUTOR_ID = #{tutorId}");

        }

        } .toString();

        }

       }

    public interface TutorMapper

    {

    @UpdateProvider(type = TutorDynaSqlProvider.class,

    method ="updateTutor")

    int updateTutor(Tutor tutor);

    }

     4 @DeleteProvider

    我们可以使用@DeleteProvider注解创建动态地DELETE语句,如下所示:

    [java]

    publicclassTutorDynaSqlProvider

    {

    publicString deleteTutor(inttutorId)

    {

    returnnewSQL()

    {

    {

    DELETE_FROM("TUTORS");

    WHERE("TUTOR_ID = #{tutorId}");

        }

         } .toString();

         }

        }

    publicinterfaceTutorMapper

    {

    @DeleteProvider(type = TutorDynaSqlProvider.class,

    method ="deleteTutor")

    intdeleteTutor(inttutorId);

    }

    相关文章

      网友评论

        本文标题:springboot-整合mybatis,security

        本文链接:https://www.haomeiwen.com/subject/yymsjxtx.html