springboot-整合mybatis,security

weixin_33907511發表於2018-03-29

最近做專案用到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();

}

3145530-e3de09b48c8bae2d

例如,看下面的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);

}

作者:誰在烽煙彼岸

連結:https://www.jianshu.com/p/3e5e1f5a85d1

來源:簡書

著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

相關文章