跳到主要內容

Spring boot v1.5 (五) JDBCTemplate

    我個人是較推崇 JPA的,不過有些情況下,或是架構設計上,會需要純SQL的方式進行,但是像教科書介紹的方式進行,在實務上很難看到,太難用、程式太醜、修改太複雜等等都是要克服的問題,不可能期望所有開發者都是同一高等級的,JDBCTemplate某程度簡化了使用SQL的繁雜度,若是需要大量的純SQL時,JDBCTemplate絕對是首選,也會介紹JDBCTemplate如增刪修查方式、Connection Pool設定及帳密加密的方式等等。

  • 預先準備項目:請先下載安裝 PostgreSQL,並建立一個DB(louisz)及Table(users),DDL如下:
CREATE DATABASE louisz
    WITH 
    OWNER = louisz
    ENCODING = 'UTF8'
    LC_COLLATE = 'Chinese (Traditional)_Taiwan.950'
    LC_CTYPE = 'Chinese (Traditional)_Taiwan.950'
    TABLESPACE = pg_default
    CONNECTION LIMIT = -1;

CREATE TABLE public.users
(
    id integer NOT NULL,
    name character varying COLLATE pg_catalog."default",
    email character varying COLLATE pg_catalog."default",
    mobilenumber character varying COLLATE pg_catalog."default",
    CONSTRAINT user_pkey PRIMARY KEY (id)
)
WITH (
    OIDS = FALSE
)
TABLESPACE pg_default;

學習目的:使用自訂屬性設定檔、屬性一些進階的使用。
學習時數:3.5hr
教學影片:

pom.xml 說明
spring-boot-starter-web:配置 Web Project所需的函式庫。
spring-boot-starter-test:配置 unit or mock test 所需的函式庫。
spring-boot-starter-actuator:配置監控spring boot所需的函式庫,後續spring cloud會使用到,所以一開就導入。
spring-boot-starter-jdbc:配置使用jdbc所需的函式庫。
postgresql:配置postgresql連接Driver所需的函式庫。
jasypt-spring-boot-starter:加解密所需的函式庫。
example5.properties JDBC設定檔說明
#DB設定資訊
#PostgreSQL JDBC URL
spring.datasource.url= jdbc:postgresql://localhost:5432/louisz
#DB使用者帳號
spring.datasource.username=louisz
#DB使用者密碼已經加過密的,請使用自己產生的
spring.datasource.password=ENC(xOSgfOF9jzB8jpYSB1O+4jEobziG16pA)

產生亂碼值的指令
java -cp ~/.m2/repository/org/jasypt/jasypt/1.9.2/jasypt-1.9.2.jar  org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="contactspassword" password=supersecretz algorithm=PBEWithMD5AndDES
input:需要加密的資訊
password:壓密KEY,可以自己定義
結果應該像是這樣,OUTPUT就是被加密過後的值

----ENVIRONMENT-----------------

Runtime: Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 24.45-b08



----ARGUMENTS-------------------

algorithm: PBEWithMD5AndDES
input: contactspassword
password: supersecretz



----OUTPUT----------------------

XcBjfjDDjxeyFBoaEPhG14wEzc6Ja+Xx+hNPrJyQT88=

程式碼說明
  • Example5.java
package louisz.springboot.example5;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;

/**
 * Louisz Spring boot introduce ex.5
 *
 */

@SpringBootApplication
@PropertySource(name = "EncryptedProperties", value = "classpath:example5.properties")//針對需加解密的設定檔檔名及位置
public class Example5 {
 /**
  * 程式執行起點
  * 
  * @param args
  */
 public static void main(String[] args) {
  SpringApplication.run(Example5.class, args);

 }

}
  • UserService.java
package louisz.springboot.example5;

import java.util.List;

import louisz.springboot.example3.User;

public interface UserService {
 /**
  * 新增一筆User資料
  * 
  * @param User
  */
 void merge(User user);

 /**
  * 刪除傳入相同姓名的資料
  * 
  * @param name
  */
 void deleteByName(String name);

 /**
  * 查詢所有資料,並回傳List物件
  */
 List listAll();

 /**
  * 查詢特定id資料,並回該User Object
  */
 
 User findById(Long id);
 
 /**
  * 删除所有用户
  */
 void deleteAllUsers();

 /**
  * 依據傳入的id,依據傳入的User物件,更新資料表中相同id的資料
  * 
  * @param id
  * @param user
  */
 void updateUser(Long id, User user);
}

  • UserServiceImpl.java
package louisz.springboot.example5;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import louisz.springboot.example3.User;

@Service
public class UserServiceImpl implements UserService {

 @Autowired
 private JdbcTemplate jdbcTemplate;

 @Override
 public void merge(User user) {
  jdbcTemplate.update("insert into users(id,name,email,mobilenumber) values(?, ?,?,?)", user.getId(),
    user.getName(), user.getEmail(), user.getMobilenumber());
 }

 @Override
 public void deleteByName(String name) {
  jdbcTemplate.update("delete from users where name = ?", name);
 }

 @Override
 public List listAll() {
  return jdbcTemplate.query("select * from users", new BeanPropertyRowMapper(User.class));
 }

 @Override
 public void deleteAllUsers() {
  jdbcTemplate.update("delete from users ");
 }

 @Override
 public void updateUser(Long id, User user) {
  jdbcTemplate.update("update users set name = ? where id = ?", user.getName(), id);
 }

 @Override
 public User findById(Long id) {
  return (User)jdbcTemplate.queryForObject(
    "select * from users where id = ?", new Object[] { id },
    new BeanPropertyRowMapper(User.class));
 }

}

  • TestUserServiceImpl.java
package louisz.springboot.example5;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.junit4.SpringRunner;

import louisz.springboot.example3.User;

//spring boot 1.4以後的方式
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class TestUserServiceImpl {

 @Autowired
 private UserService userSerivce;// 注入UserService
         // interface,實際instance會呼叫UserServiceImpl物件

 @Before
 public void setUp() {
  // 先清除所有資料
  userSerivce.deleteAllUsers();
 }

 @Test
 public void test() throws Exception {
  /*
   * 進行單元測試,先規劃相關情境
   */
  User user1 = new User();
  user1.setId(1l);
  user1.setEmail("louisz6ster@gmail.com");
  user1.setName("user1");
  user1.setMobilenumber("0912345678");

  User user2 = new User();
  user2.setId(2l);
  user2.setEmail("louisz6ster@gmail.com");
  user2.setName("user2");
  user2.setMobilenumber("0912345678");

  User user3 = new User();
  user3.setId(3l);
  user3.setEmail("louisz6ster@gmail.com");
  user3.setName("user3");
  user3.setMobilenumber("0912345678");
  // 新增三個User資料
  userSerivce.merge(user1);
  userSerivce.merge(user2);
  userSerivce.merge(user3);

  // 查詢全部資料筆數是否吻合,確認新增成功
  Assert.assertEquals(3, userSerivce.listAll().size());
  // 刪除資料
  userSerivce.deleteByName("user1");
  userSerivce.deleteByName("user2");
  // 查詢全部資料筆數是否吻合,確認刪除成功
  Assert.assertEquals(1, userSerivce.listAll().size());
  
  //更新User3姓名跟email
  user3.setName("Jessie");
  userSerivce.updateUser(user3.getId(), user3);
  
  //查詢資料表中User3的資料是否更新成功
  User newUser3 = userSerivce.findById(user3.getId());
  Assert.assertEquals(user3.getName(), newUser3.getName());
  
 }

}

單元測試看結果,執行時請加上-Djasypt.encryptor.password=supersecretz
Github code(louisz.springboot.example5)
參考連結:
http://blog.didispace.com/springbootdata1/
https://www.ricston.com/blog/encrypting-properties-in-spring-boot-with-jasypt-spring-boot/
https://github.com/ulisesbocchio/jasypt-spring-boot


留言

這個網誌中的熱門文章

使用Apache Http Server進行Proxy和LoadB alance

環境概述 OS:Linux Apache Http Server:2.2.21 安裝可以使用rpm或是抓source下來compile,建議前者 rpm –ivh apache-http-xxx.rpm 這裡請注意一下安裝的版本 http.conf 參數設定 Proxy < VirtualHost *:80>      ProxyPass targetPath fromPath | fromUrl < VirtualHost/>  範例如下 < VirtualHost *:80>      ProxyPass /app http://DomainName或IP:8888/app      ProxyPassReverse /app http://DomainName或IP:8888/app < VirtualHost/> 上述的參數設定為,將某主機的http通訊協定下的Web application(app),對應到本台Web Server的app下。這樣的Proxy架構的設定對企業內的Web應用程式相當有用處,若是遇到Web Application Server掛點只需要修改Proxy對應,不需要動到dns等等,是個滿便宜的Proxy架構設定喔。﹝不過要注意Web Application要注意redirectc和forward等的撰寫,盡量不要有絕對IP的出現﹞

IBM MQ Server To Server的簡易設定

IBM MQ 的STS建置方式,IBM Red Book已經說明的滿完整的,這裡稍微整理一下,步驟如下 在 MQ-A Server MQ QMGR(MQA) 上需要建立的物件定義如下: • 遠端佇列定義 PAYROLL.QUERY • 傳輸佇列定義 MQB(預設 = 遠端佇列管理程式名稱) • 程序定義 MQA.TO.MQB.PROCESS(對於 WebSphere MQ for AIX、HP-UX、Solaris 與 Windows,及 MQSeries for Compaq Tru64 UNIX 與 OS/2 Warp,並非必要) • 傳送端通道定義 MQA.TO.MQB • 接收端通道定義 MQB.TO.MQA • 本端佇列定義 MQ2 以下是必須建立在 MQ-B Server MQ QMGR(MQB) 中的物件定義: • 遠端佇列定義 PAYROLL.RESPONE • 傳輸佇列定義 MQA(預設值=遠端佇列管理程式名稱) • 程序定義 MQB.TO.MQA.PROCESS(對於 WebSphere MQ for AIX、HP-UX、Solaris 與 Windows,及 MQSeries for Compaq Tru64 UNIX 與 OS/2 Warp,並非必要) • 傳送端通道定義 MQB.TO.MQA • 接收端通道定義 MQA.TO.MQB • 本端佇列定義 MQ4 1.先啟動MQ-A Server上的QMGR(MQA),並使用Runmqsc進入。 2.在佇列管理程式 MQA 上執行下列指令。 遠端佇列定義 DEFINE QREMOTE(PAYROLL.QUERY) DESCR('MQA 的遠端佇列') REPLACE + PUT(ENABLED) XMITQ(MQB) RNAME(MQ4) RQMNAME(MQB) 註: 遠端佇列定義並非實體的佇列,但卻是引導訊息至傳輸佇列 (MQB) 的一種方式,以便能將訊息送至佇列管理程式 MQB。 傳輸佇列定義 DEFINE QLOCAL(MQB) DESCR('對 MQB 的傳輸佇列') REPLACE + USAGE(XMITQ) PUT(ENABLED) GET(ENABLED) TRIGGER TRIGTYPE(FIRST) + INITQ(SYSTEM.CHANN

IReport字型下拉選單中文亂碼

這個問題其實也不是很大啦,不過當你有很多的中文字型檔的時候可能就不知道要選哪一個,啟動IReport後,開啟報表後會發現左邊下拉選單中,最下面的字型清單中有出現方框,顯示不出該字型的名稱,這幾個字型應該是判斷新細明體,標楷體及細明體,如下圖 下載IReport的Source Code來檢查一下,it.businesslogic.ireport.gui.MainFrame發現這個JComboBox有特別設定Arial字型,當然只要是中文的都顯示不出來ㄚ,所以點掉這一行後重新編譯,嘿嘿就可以了。 jComboBoxFont.setFont(new java.awt.Font("Arial", 0, 11)); 我目前使用的版本為 IReport-3.0.0-src