Chủ Nhật, 12 tháng 11, 2017

Spring boot: spring security + thymeleaf

With previous post "spring boot: hello world + thymeleaf", you can create a spring boot application.
Now, in this post, i will demo integrated spring boot with spring mvc.
Ok, let's get started.

Step1: create spring boot project with STS

Spring boot: hello world + thymeleaf

In this post, i am going to demo spring boot using tomcat (embed) and thymeleaf template engine.

Tools:
- spring tool suite (STS): Version: 3.9.1.RELEASE
- maven 3.5
- spring boot version 1.5.8
- Thymeleaf templating engine, including integration with Spring.

Step1: create new spring starter project





Structure of project after create.


Pom.xml (auto generate for us)
<?xml version="1.0" encoding="UTF-8"?>  
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
      <modelVersion>4.0.0</modelVersion>  
      <groupId>com.shine2share</groupId>  
      <artifactId>springboot_demo1</artifactId>  
      <version>0.0.1-SNAPSHOT</version>  
      <packaging>jar</packaging>  
      <name>springboot_demo1</name>  
      <description>Building project by spring boot</description>  
      <parent>  
           <groupId>org.springframework.boot</groupId>  
           <artifactId>spring-boot-starter-parent</artifactId>  
           <version>1.5.8.RELEASE</version>  
           <relativePath/> <!-- lookup parent from repository -->  
      </parent>  
      <properties>  
           <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
           <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>  
           <java.version>1.8</java.version>  
      </properties>  
      <dependencies>  
           <dependency>  
                <groupId>org.springframework.boot</groupId>  
                <artifactId>spring-boot-starter-thymeleaf</artifactId>  
           </dependency>  
           <dependency>  
                <groupId>org.springframework.boot</groupId>  
                <artifactId>spring-boot-starter-web</artifactId>  
           </dependency>  
           <dependency>  
                <groupId>org.springframework.boot</groupId>  
                <artifactId>spring-boot-starter-test</artifactId>  
                <scope>test</scope>  
           </dependency>  
      </dependencies>  
      <build>  
           <plugins>  
                <plugin>  
                     <groupId>org.springframework.boot</groupId>  
                     <artifactId>spring-boot-maven-plugin</artifactId>  
                </plugin>  
           </plugins>  
      </build>  
 </project> 


SpringbootDemo1Application.java (run this class to start spring boot application)
package com.shine2share;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringbootDemo1Application {

 public static void main(String[] args) {
  SpringApplication.run(SpringbootDemo1Application.class, args);
 }
}


Step2: create a simple controller and simple html page (index.html) under src/main/resources -> templates:



HomeController.java
package com.shine2share.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller public class HomeController { @RequestMapping("/")
model.addAttribute("name", "Spring Developer.");
public String sayHello(Model model) { return "index"; }
}

index.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" 
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
<meta charset="UTF-8" />
<title>Home</title>
</head>
<body>
  <h1><span th:text="'Hello: ' + ${name}"></span></h1>
</body>
</html>

ok.
check result with following url:

if your application don't show like above.
you can check your spring boot is running: (click to image to show full size)

if it stopped, you can run it again, right mouse click on project -> run as -> spring boot app
check url again.
happy coding.

Thứ Bảy, 4 tháng 11, 2017

Spring mvc: tạo và run ứng dụng đầu tiên



Công cụ sử dụng:
STS (spring tool suite)
jdk 1.8
maven 3.5.0
tomcat: 9.0

Các công cụ trên bạn có thể tải về từ trang chủ, cài đặt và cấu hình environment cho nó.
Ở bài này, mình mặc định là các bạn đã biết cách cài và cấu hinh đường dẫn path (trong windows).

Ok, bắt đầu học spring mvc, qua việc tạo và chạy thử ứng dụng đầu tiên.

Khởi động STS (thằng này được phát triển dựa trên eclipse) nên giao diện rất giống eclipse.

Tạo 1 project Maven. (dùng maven vì nó có nhiều cái hay - hay như thế nào thì you can google) và đặc biệt là trong project thực tế thấy toàn dùng maven. :)

Đơn giản là File -> New -> Maven Project (nếu ko thấy xuất hiện Maven Project trong list chọn thì bạn chọn vào other rồi gõ từ Maven vào ô Wizard. Nó sẽ xuất hiện và bạn chọn Maven Project.


và nếu ko thấy trong list trên thì chọn other như này đây:


Ok, khi chọn xong thì màn hình sau xuất hiện:




ở đây thì bạn cần quan tâm.
 - là bạn có thể click vào Create a simple proect (skip archetype selection)
bạn có thể click vào đây. ko click cũng chẳng sao. Nếu click vào thì nó sẽ tạo 1 cấu trúc project maven có những mục cơ bản.
- nếu bạn muốn tạo project để viết ứng dụng web app thì nên để mặc định (ko click vào cái trên) và nhấn next.
- tiếp theo sẽ xuất hiện cửa sổ:



ở mục Catalog thì bạn click vào Internal, rồi kéo xuống dưới cùng chọn  maven-archetype-webapp
ok, tiếp


Group id: điền tên miền website (theo chuẩn là vậy)- chứ bạn viết linh tinh cũng đc.
Artifact id: tên project.
những thứ dưới ko cần quan tâm. Để mặc định
Nhấn vào Finish, chờ 1 tý là project maven được tạo ra.



bạn lưu ý chỗ mũi tên đỏ. Nếu nó ko như hình thì bật nó lên bằng cách




click other rồi chọn Java EE.



ok, tiếp theo ta thêm thư viện, với maven project thì việc thêm thư viện bạn sẽ thêm trong file pom.xml (project object model)

tạm thời, chúng ta thêm các thư viện sau, cái này bạn chỉ cần copy paste, ko cần gõ làm gì cho mệt

paste xong bạn Ctrl + S để nó lưu và tải các thư viện.
Tiếp theo bạn làm như hình.


rồi copy nội dung sau vào web.xml




bạn tạo thêm vài file như hình trên.

MyServlet-servlet.xml- trong file này bạn lưu ý chỗ này:  <context:component-scan base-package="com.shine2share" /> điền package đúng với package của bạn nhé.

helloworld.jsp


HelloWorld.java

Ok, nếu đã có tomcat server thì chạy thôi.
Chuột phải vào project, run as, run on server. Nếu bạn nào chưa có server thì add vào nhé.

khi chạy lên thì đường dẫn mặc định là như này

để chạy cái helloworld.jsp thì bạn thêm vào đường dẫn như hình

Ok, kết quả là nó đã mapping đc với nhau. Nếu gặp lỗi gì thì comment nhé.

Thứ Ba, 31 tháng 10, 2017

Kotlin cơ bản: Function (tiếp)


Top - Level Function:
Là Function định nghĩa ngoài Class, Object, Interface. Function loại này có thể gọi trực tiếp luôn mà không cần tạo đối tượng.
Nếu ai đã từng code java thì top level function có thể hiểu là thay thế cho các static method.
ví dụ về top-level function:
package com.shine2share

fun printName(name: String): String {
    return name
}

Để sử dụng top level function trong package khác thì ta chỉ việc import nó là ok
package com.share2study

import com.shine2share.printName

fun myFun(): String {
    return printName("Dycky")
}

--> import xong, ta gọi trực tiếp hàm luôn

Lambda Expression in Kotlin
Hay còn gọi là Function Literal

- phải có cặp ngoặc nhọn {}
- ko có fun keyword
- ko có bất kỳ 1 access modifier nào ( private, public, protected)
- nó là ẩn danh (anonymous) có nghĩa là ko có tên function
- ko có kiểu trả về
- parameters ko đc bao bọc bởi cặp ( )

--> gán lambda expression với 1 biến và thực thi nó.

ví dụ 1: ko param
// lambda expression with no param
val xinChao = {println("Xin chao! Toi la Kotlin Dev.")}
fun main(args: Array<String>) {
    xinChao()
}

ví dụ 2: 1 param
// lambda expression with 1 param
val xinChao = {name: String -> println("Xin chao! $name la Kotlin Dev.")}
fun main(args: Array<String>) {
    xinChao("Ducky")
}

ví dụ 3: 2 param
val calSum = {num1: Int, num2: Int -> println("Sum of num1 and num2 is: " + (num1+num2))}
fun main(args: Array<String>) {
    calSum(1,2)
}


Lambda expression có thể làm param cho Function
fun main(args: Array<String>) {
    println(stringList.last()) // "Hola"    println(stringList.last({ s: String -> s.length == 8})) // "Xin chao"}

val stringList: List<String> = listOf("Hello", "Xin chao", "Hola")

Có thể bỏ dấu ngoặc ( ) nếu tham số truyền vào là lambda expression
println(stringList.last{ s: String -> s.length == 8}) // "Xin chao"

it keyword: tạo ra tự động bởi compiler - Kotlin sẽ tự hiểu "it" là stringList hiện tại.
fun main(args: Array<String>) {
    println(stringList.last{ it.length == 8}) // "Xin chao"}

val stringList: List<String> = listOf("Hello", "Xin chao", "Hola")

Local return in lambda expression
xét đoạn code sau
fun main(args: Array<String>) {
    printName()
}

fun printName() {
    val intList = listOf(1, 2, 3, 4, 5)
    intList.forEach {        if (it % 2 == 0) {
            return        }
    }    println("Ket thuc ham printName()")
}

dòng lệnh
println("Ket thuc ham printName()")
sẽ ko in ra theo mong muốn.
Để fix lỗi trên ta chỉ cần thêm 1 nhãn (hoặc tag name) vào sau return
intList.forEach {    if (it % 2 == 0) {
        return@forEach    }
}

bạn cũng có thể tự định nghĩa nhãn cho riêng mình
fun printName() {
    val intList = listOf(1, 2, 3, 4, 5)
    intList.forEach myLabel@{        if (it % 2 == 0) {
            return@myLabel        }
    }    println("Ket thuc ham printName()")
}

Member Function
là loại function định nghĩa trong class, object hay interface.
ví dụ:
class Circle {
    fun calArea(radius: Double): Double {
        return Math.PI * Math.pow(radius, 2.0)
    }
}

Cách thức gọi hàm như sau
fun main(args: Array<String>) {
    val circle = Circle()
    println("Dien tich hinh tron la: " + circle.calArea(3.0))
}

Anonymous Function
- ko có tên
- có fun keyword
- có thân hàm (body)
























Thứ Hai, 30 tháng 10, 2017

Kotlin cơ bản: Function


Function - khai báo trong Kotlin với từ khóa fun.
ví dụ:

fun sayHello(name: String) : String {
        return "Hello " + name
}

hoặc dùng ký hiệu $ để lấy giá trị của name như sau:
fun sayHello(name: String) : String {
        return "Hello $name"}

Function trên nhận 1 tham số truyền vào là name, kiểu String.
Kiểu trả về của function cũng là String.

Gọi hàm:

fun main(args: Array<String>) {
        val result: String = sayHello("Viet nam")
        println(result)
    }

Trong java hay c++ nếu function không trả về gì thì dùng từ khóa void. Nhưng trong Kotlin thì dùng từ khóa Unit

ví dụ:
fun print(name: String): Unit {
    println(name)
}

Bỏ qua từ khóa Unit thì chương trình vẫn chạy bình thường.

Biến hàm thành biểu thức trong Kotlin:
ví dụ:
fun getArea(width: Long, height: Long): Long {
    return width*height
} 

hàm trên chúng ta có thể viết lại như sau:
fun getArea(width: Long, height: Long) = width*height

có thể thêm kiểu trả về của function nếu bạn muốn
fun getArea(width: Long, height: Long): Long = width*height

Trong Kotlin khi gọi hàm có nhiều hơn 1 tham số truyền vào, ta ko nhất thiết phải truyền các tham số theo thứ tự bằng cách sử dụng tên của tham số.
ví dụ:
getArea(height = 14, width = 12)

hàm getArea theo định nghĩa thì width là tham số 1, height là tham số 2. Nhưng bằng cách chỉ định tên của tham số thì vấn đề thứ tự tham số truyền vào không quan trọng nữa.

Khi định nghĩa 1 hàm có tham số truyền vào, chúng ta có thể gán giá trị mặc định cho tham số:
fun getArea(width: Long, height: Long = 10): Long = width*height 

ta thấy tham số thứ 2 height được gán giá trị mặc định là 10.
nên khi gọi hàm, nếu ta ko truyền vào giá trị cho tham số height thì Kotlin sẽ lấy giá trị mặc đinh
getArea(12)

nếu trường hợp bạn truyền tham số đầy đủ thì Kotlin sẽ tính theo giá trị bạn truyền vào.

Trong java thì ko có khái niệm giá trị tham số truyền vào có giá trị mặc định như trên, nên nếu muốn khi trong dự án mà dùng cả Kotlin và Java thì ta thêm chú thích (annotation) sau cho hàm:

@JvmOverloadsfun getArea(width: Long, height: Long = 10): Long = width*height

như vậy khi biên dịch thì trình biên dịch sẽ sinh ra thêm 1 hàm overload (không có tham số mặc đinh)
mã java sinh ra thêm khi biên dịch nếu thêm @JvmOverloads
long getArea(long width);

Hàm không giới hạn tham số truyền vao
ta thêm từ khóa vararg trước tên tham số truyền vào
fun sayHello(vararg names: String) {
    for(name in names) {
        println("Hello $name")
    }
}

khi gọi hàm, truyền vào nhiêu tham số thì sẽ in ra mấy nhiêu giá trị name
sayHello("xin chao", "hello", "hola")

Hàm trả về 2 giá trị
ta thêm từ khóa Pair trong kiểu trả về của hàm
fun returnTwoValue(id: Int): Pair<Int?, Int?> {

    val values1: Map<Int, Int> = mapOf(1 to 100, 2 to 200, 3 to 300)
    val values2: Map<Int, Int> = mapOf(1 to 1000, 2 to 2000, 3 to 3000)

    val value1 = values1[id]
    val value2 = values2[id]
    return Pair(value1, value2)
}

2 giá trị trả về có thể khác kiểu
fun returnTwoValue(id: Int): Pair<Int?, String?> {

    val values1: Map<Int, Int> = mapOf(1 to 1, 2 to 2)
    val values2: Map<Int, String> = mapOf(1 to "Hanoi", 2 to "Saigon")

    val value1 = values1[id]
    val value2 = values2[id]
    return Pair(value1, value2)
}

Lấy giá trị trả về
println(returnTwoValue(1).first)
println(returnTwoValue(1).second)

Nếu muốn trả về 3 giá trị, Kotlin hỗ trợ với từ khóa Triple
fun getNameAddressAndAge(id: Int): Triple<String?, String?, Int?> {

    val Names: Map<Int, String> = mapOf(1 to "My", 2 to "Nam")
    val Addresses: Map<Int, String> = mapOf(1 to "Hanoi", 2 to "Saigon")
    val Ages: Map<Int, Int> = mapOf(1 to 12, 2 to 22)

    return Triple(Names[id], Addresses[id], Ages[id])
}

Lấy giá trị trả về
println(getNameAddressAndAge(1).first)
println(getNameAddressAndAge(1).second)
println(getNameAddressAndAge(1).third)


Thứ Hai, 23 tháng 10, 2017

Kotlin cơ bản: Ranges và Collections

1. Ranges

Kotlin thì ko có vòng lặp for như thông thường như của java, c++

Ex: for(int i = 0; i < 10; ++i)

Để thay thế cho vòng lặp for kiểu trên, Kotlin dùng khái niệm Ranges.

Ranges là 1 cái khoảng giữa 2 giá trị, thông thường là số, 1 bắt đầu và 1 kết thúc.

Sử dụng dấu .. giữa  2 số này.

Ex1: val oneToFive = 1..5

code lặp sẽ như sau

for(number in oneToFive) {
    print(number)
}

Lưu ý là số thứ 2 (trong trường hợp trên là 5) cũng bao gồm trong Ranges (lặp đến cả số 5)

Ex2: val rangeOfChar = 'a'..'z'

for(i in rangeOfChar) {
    print(i)
}

cũng có thể viết như sau:

for(i in 'a'..'z') {
    print(i)
}

Để tạo 1 range ngoài sử dụng dấu .. ta còn có thể sử dụng phương thức rangeTo() có sẵn

Ex: val oneToFive = 1.rangeTo(5) // tương đương với 1..5

tương tự có phương thức downTo()

val five2One = 5.downTo(1)

nếu duyệt vòng lặp for thì nó sẽ in ra từ 5 tới 1

for(a in five2One)
print(a)

toán tử in trong ranges dùng để kiểm tra 1 giá trị có tồn tại trong (in) ranges hay ko


if( 1 in five2One) {
    print("1 in five2One")
}

2. Collections

Collection dùng để lưu trữ một nhóm các đối tượng liên quan nhau trong bộ nhớ.

Kotlin xây dựng 1 bộ API Collection (Interface) , khi biên dịch thì nó sẽ gọi đến các cái thằng thực thi của nó (implementation).














Kotlin cơ bản: Null, Loop, Condition

1. Null

Nếu bạn đã học và code java thì chắc hẳn bạn cũng đã từng gặp và thậm chí là gặp nhiều lần NullPointerException. Exception này xảy ra khi bạn đọc 1 thuộc tính (property) hoặc gọi 1 method của 1 object mà nó đang tham chiếu (reference) tới giá trị null.

Với Kotlin thì bạn sẽ ko cần phải lo lắng về Exception này nữa. Theo mặc định thì biến trong Kotlin sẽ ko có giá trị Null, trừ khi bạn khai báo rõ ràng nó là Null.

Như ví dụ sau sẽ ko biên dịch (compiler)


val name: String = null // will not compile

Nếu bạn cố tính muốn gán giá trị null thì thêm dấu ? sau kiểu data, như sau:


val name: String? = null // will compile
name = "Nguyen The Lam" // new value is "Nguyen The Lam"

Tương tự cho các kiểu data khác: Long? Int? Object? ...

Khi bạn cố tính gán giá trị null cho 1 biến thì bạn sẽ ko thể gọi các method, property theo cách . (chấm) thông thường nữa.

Thay vào đó, bạn dùng ?. (tổ hợp dấu chấm hỏi và dấu chấm), như sau để gọi hàm, property.


val name: String? = null
print(name?.length) // will compile and print "null"

Giá trị null mà compiler in ra ở trên là 1 string "null".

Có thể gán lại giá trị null cho 1 biến khác như sau


val name: String? = null
val len: Int? = name?.length
print(len) // will compile and print "null"

Nếu vẫn muốn tạo ra NullPointerException thì thay ?. bằng !!. (ko khuyến khích)


val name: String? = null
val len: Int? = name!!.length
print(len) // NullPointerException error

Toán tử ?: hay còn gọi là toán tử Elvis

được sử dụng để cung cấp 1 giá trị thay thế cho 1 biến nếu nó null


val fullName = null
val name: String = fullName?: "Ducky"
print(name) // will compile and print "Ducky"

Đoạn code trên, compiler sẽ gán giá trị Ducky cho biến name, vì fullName = null,
Nếu fullName khác null thì giá trị của fullName sẽ gán cho name thay vì Ducky.

2. Loop

Các vòng lặp trong Kotlin: for - while - do while

- for loop


for (value in range) {
    // Execute code
}

trong đoạn code trên: in là 1 toán tử chỉ ra rằng value (giá trị) in (trong) range (1 giải giá trị)

Ex:


for (number in 1..9) {
     print("$number ") // will print  1 2 3 4 5 6 7 8 9
}

Duyệt thông qua chỉ số mảng (Array):

Có thể dùng withIndex() function hoặc indices property

- withIndex() function


val numbers = intArrayOf(1,2,3,4,5)
for ((index, value) in numbers.withIndex()) {
    print("$index index value is $value\n")
}

thực thi đoạn code trên, giá trị in ra sẽ là:


0 index value is 1
1 index value is 2
2 index value is 3
3 index value is 4
4 index value is 5

- indices property


val numbers = intArrayOf(1,2,3,4,5)
for (index in numbers.indices) {
    print("$index index value is ${numbers[index]}\n")
}

thực thi đoạn code trên, giá trị in ra:


0 index value is 1
1 index value is 2
2 index value is 3
3 index value is 4
4 index value is 5

3. Cấu trúc điều kiện: if, if - else, when

- if - tương tự java


val check= 10
if (check % 2 == 0) {
    print("$check chia hết cho 2") // 10 chia hết cho 2
}

có thể dùng is keyword để check điều kiện if


if (number is Int) {
    print("$number is an integer")
}

- if - else


val number = 3
if (number % 2 == 0) {
    print("$number chia hết cho 2")
} else {
    print("$number ko chia hết cho 2") // 3 ko chia hết cho 2
}

Một điểm lưu ý với câu lệnh if - else trong Kotlin là:

if - else còn có thể là 1 biểu thức trong Kotlin


val number = 3
val result = if (number % 2 == 0) {
    "$number chia hết cho 2"
} else {
    "$number ko chia hết cho 2"
}
print(result) // 3 ko chia hết cho 2

Lưu ý là nếu có nhiều giá trị trong if - else thì giá trị trả về của biểu thức là giá trị cuối cùng.

Ex:


val result = if (number % 2 == 0) {
    "Divisible by 2"
    "Number is $number" // Nếu thực thi thì chỉ string này được trả về
} else {
    "Not divisible by 2"
    "Number is $number"
}

- when

when trong Kotlin là 1 sự thay thế cho swith trong java, c++

when được giới thiệu thì ngắn gọn và nhiều tính năng hơn so với swith trong java, c++

các kiểu data áp dụng cho when: By, Short, Int, String, và bất kỳ object nào


fun guessTheNumber(number: Int) {
    when (number) {
        1 -> println("number is 1")
        2 -> println("number is 2")
        3 -> println("number is 3")
        else -> println("number is neither 1, 2 or 3")
    }
}

when cũng có thể ko cần đối số (argument)


fun guessTheNumber(number: Int) {
     
    when {
        number == 1 -> println("number is 1")
        number == 2 -> println("number is 2")
        number == 3 -> println("number is 3")
        else -> println("number is neither 1, 2 or 3")
    }
}

Nếu muốn thực thi nhiều hơn 1 lệnh trong 1 nhánh (branch) thì dùng cặp { } để bao code lại.


val number = 2
when (number) {
    1 -> println("number is 1")
    2 -> {
        println("number is 2")
        println("it is an even number")
    }
    3 -> println("number is 3")
}

when trong Kotlin cũng có thể làm được như sau


val number = 2
when (number) {
    1, 2 -> println("number is either 1 or 2") // lệnh này sẽ đc thực thi. (hoặc là 1 hoặc là 2)
    3 -> println("number is 3")
}