# 03.2-Data Stores and Rersistence Lesson1: Data in Multitier Architecture
###### tags: `Udacity`
[ToC]
# 01 Introduction to Data in Multitier Archetecture
**Data in Multitier Architecture**
{%youtube YcfmFY-iUpI%}
Multitier Architecture is a term used to refer to a form of design that separates various functions of the application into their own layers. In this course, we’ll focus on how data in our application is defined and used across these layers.
Entities are used to negotiate between:
* The object representation of data in Java.
* The table representation of data in a database.
> Yout are Here

# 02 Entities Exercise 0
{%youtube OkGpLJZaRk8%}
Follow the steps in the task list to create a new Spring Boot application and create the following controller class:
```java
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping
public String test(){
return "Data Structures and Persistence are pretty good.";
}
}
```
# 03 Entity Design Overview
**Entity Design Overview**
{%youtube mHCXuDeXQeI%}
Programs can represent all kinds of ideas, so the tools we use to describe our data must be flexible. The variables, which are the building blocks of our Entities, are like words that can mean different things to different people. We will use Entities to communicate ideas to our database.
> Translating Ideas Between Domains

**Java Persistence API (JPA)**
A specification describing how to manage relational data.
**Hibernate**
An implementation of the JPA Specification. You can access [Hibernate’s documentation page here](https://hibernate.org/orm/).
**Lesson Outline**
* Value vs. Entity types
* BasicTypes in Java and JDBC
* Identifiers
* Relationships
* Inheritance
# 04 Values vs. Entity Types
**Values and Entity Types**
{%youtube FsHP3y-BG4Y%}
**POJO or "Plain Old Java Object"**
A Java object that contains data, but no methods to describe behavior.
**Entity Types**
Java classes that describe a collection of data.
* Contain Data only, no behavior
* Represented by a table in the database
**Value Types**
The data inside an Entity.
* Primitives like int, boolean, char
* Classes that only represent a single piece of data, like BigInteger or LocalDate
* Represented by a column in the database
> Primitives: 在Java 當中內建好的資料型態(primitive data type)
**@Entity and @Table Annotations**

To identify which Java classes we wish to consider as Entities, we added the `@Entity` annotation before the class name. This informs(告知) Hibernate that this class should be stored in the database. Each Entity class will be associated with a table of the same name, or you can specify your own table name using the `@Table` annotation at the class level. The attributes of the classes automatically become columns of the same name, and we can change the names and properties of the columns with the `@Column` annotation.
As we can see in this example, we’ve added the `@Entity` annotation to our Person class, and we have specified that the `favoriteComposer` field should be stored in a column called “composer”.
One additional point to remember about Entity classes is that they must provide a public or protected no-arg(無參數) constructor. Java automatically creates one for you if no constructor is specified, but if you create one or more of your own constructors for the class, you’ll also have to make sure to include a no-arg version as well.
For additional details on mapping types, see the [official Hibernate documentation on mapping types.](https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#mapping-types)
# 05 Basic Types
**Basic Types**
{%youtube Zgxutge1bH0%}
**Basic Types**
Basic Types map a single database column to a single, non-aggregated Java type. Here are some examples of basic types:

[Full List of Hibernate standard BasicTypes.](https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#basic)
Hibernate selects default BasicTypes for you, but you can override by specifying the `@Type` annotation, as below.
>An example of using the `@Type` Annotation to Force a Typing

Each BasicType should only map a single value to a single column in the database. Do not attempt to serialize objects or lists of primitives into a single column. Doing so violates First Normal Form of database design, preventing standard relational functioning.
>Basic Types should Map to Single Values, note Composite Values

**Serialization(序列化)**
Tranforming your data into a format that can be stored and reconstructed later.
**First Normal form**
Each attribute of a table contains only atomic values.
**Atomic (不可分割性)**
Representing a single peice of data; indivisible.
感覺像是collection的資料擠在一個值裡面
==ShannonNote==
Hibernate懂得如何把java types map 到相應的database type
> 從jdbc轉變成java object
> * 簡單來說,會使用ResultSet(之前android學過)來取得jdbc查詢結果

> 將java object轉變成jdbc裡面的資料
> * 然後透過PreparedStatement將java object裡面得資料一筆筆放入jdbc裡面

**Warning about creating new types**

# 06 Identifiers
{%youtube urizLUMjgbA%}
All Entities must define an identifier that uniquely identifies them. We express this by using the `@Id` annotation.
```java
@Entity
public class Person {
@Id
@GeneratedValue
Long id;
/* rest of class */
}
```
Valid identifier types are:
* Any Java primitive type
* Any primitive wrapper type (like `Long`, or `Boolean`)
* A `String`
* `java.sql.Date` or `java.util.Date`
* `java.math.BigDecimal` or `java.math.BigInteger`
The `@GeneratedValue` annotation causes this value to be assigned automatically. For more information about modifying the Id Generation strategy, see the [Hibernate Documentation on Generated Ids.](https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#identifiers-generators)
# 07 Entities Exercise 1
**Delivering Flowers**
You're creating a flower-delivery service. Create two new Java classes representing the following Entities:
1. A `Flower` for your company to sell.
2. A `Delivery` you will make.
The `Flower` should have a name, color, and price attribute. Flowers will be stored in a table called ‘plant’. Make sure the price is stored as a DECIMAL column with 12 precision and 4 decimal places (scale).
The `Delivery` should have a recipient name, address, delivery date, and delivery time. Let’s store the whole address in a single field, so make sure the column will be wide enough to hold up to 500 characters. We’ll call this column `address_full`. There should also be an attribute on the Delivery entity that shows if it is completed or not, which should show up as ‘Y’ or ‘N’ in the database.
Make sure that both the flower name and recipient name will support international language characters and that the delivery time is stored without timezone information.
Finally, make sure to add getters and setters to your classes. We won't explicitly cover getter and setter methods as they're part of the prerequisite knowledge required for this course, but they're still a very important, and required, part of many Java classes!
Consider creating a package called ‘data’ to store these entity classes. One way to structure multi-tier projects is to store each layer in a separate package and then create sub-packages for the different functional areas of your application. For example, your data package might contain a ‘delivery’ package and an ‘inventory’ package. It’s up to you! As long as your chosen organization scheme makes sense and is easy to follow.
# 08 Solution: Entities Exercise 1
**Delivering Flowers Solution**
Great job working through that exercise! Below are examples of potential solutions to the exercise.
Flower.java
```java
@Entity
@Table(name = "plant")
public class Flower {
@Id
@GeneratedValue
private Long id;
@Nationalized // should use @Nationalized instead of @Type=nstring
private String name;
private String color;
@Column(precision=12, scale=4)
private BigDecimal price; // BigDecimal is the standard Java class for currency math
/* getters and setters*/
}
```
Deliver.java
```java
@Entity
public class Delivery {
@Id
@GeneratedValue
private Long id;
@Nationalized
private String name;
@Column(name = "address_full", length = 500)
private String address;
private LocalDateTime deliveryTime; // includes both date and time - simpler than having two separate fields
@Type(type = "yes_no")
private Boolean completed;
/* getters and setters */
}
```
# 09 Composite Identifiers
{%youtube o-7P7vBO7LQ%}
Composite identifiers combine multiple attributes to define uniqueness. One way to implement this is by creating an `@Embeddable` class and using `@EmbeddedId` to identify it in your Entity.
**PersonPK.java - The Primary Key Definition**
```java
@Embeddable
public class PersonPK implements Serializable {
private int heightCm;
private String sockColor;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PersonPK personPK = (PersonPK) o;
return heightCm == personPK.heightCm &&
sockColor.equals(personPK.sockColor);
}
@Override
public int hashCode() {
return Objects.hash(heightCm, sockColor);
}
/* getters and setters */
}
```
**Person.java - The Entity**
```java
@Entity
public class Person {
@EmbeddedId
PersonPK id;
/* rest of class */
}
```
**`@Embeddable` vs. `@IdClass`**
{%youtube XH0XdB02W4E%}
The `@IdClass` annotation allows you to specify a composite primary key by shadowing the fields of your key class in the Entity. This can be useful if you must use an object as a primary key that cannot be `@Embeddable`.
**PersonPK.java**
```java
//沒有使用@Embeddable
public class PersonPK implements Serializable {
private int heightCm;
private String sockColor;
@Override
public boolean equals(Object o) {...}
@Override
public int hashCode() {...}
/* getters and setters*/
}
```
**Person.java**
- 首先指向Id的class是誰 `@IdClass(PersonPK.class)`
- 把PersonPK裡面的屬性寫進來加上`@Id`
```java
@Entity
@IdClass(PersonPK.class)
public class Person {
@Id
private int heightCm;
@Id
private String sockColor;
public PersonPK getId() {
PersonPK id = new PersonPK();
id.setHeightCm(heightCm);
id.setSockColor(sockColor);
return id;
}
public void setId(PersonPK id) {
this.heightCm = id.getHeightCm();
this.sockColor = id.getSockColor();
}
/* getters and setters */
}
```
> Comparison of @Embeddable and @IdClass Composite Keys

Additional Resources
* [Hibernate documentation on Composite Keys](https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#identifiers-composite)
---
==ShannonNote==
* 主題Composite Identifiers: 重點在Combine multiple attributes to define uniqueness.
1. 第一種使用Embeddable
* @Embeddable : 表示combine multiple attributes的class
* 需要override equals() 因為此刻不單單只比較物件的位置是否相等,而是物件內容是否相同假設我們設定說這兩個欄位作為一個PK是唯一。
* 也需要override hashcode() 因為jasjcode方法是透過object對象的地址計算出來的,object與自身相同所以對象地址也相同,那就代表hashcode出來的值也應該相等,如果重寫了equals但未重新重寫hahscode會違反hashcode的第二條規定,那就是*如果兩個對象通過equals方法是相同的那麼兩個對象調用hashcode方法必須返回相同的整數*。
* @EmbeddedId : 表示在table裡面所套用的multiple attributes as an id
2. 第二種使用IdClass
* for primary key class in java
* we need implements Serializable
* Override equals() and hashCode() method
* don't need to use the Embeddable Annocation
* For Entity
* add attribute for each our primary key from pk class with the `@Id` annotation.
* Add the `@IdClass` which pass in a reference to `personPk.class` in the class level
* Create a getter and setter for id that return and accept personPk instance.
* Unlike using an `@embeddedId`
3. Embeddable vs IdClass 的差別
* Embeddable
* More apparent which fields are part of the key.
* facilitating object-oriented querying and access through Hibernate
* PK has meaning to your application
* Pk is reused elsewhere in app
* IdClass
* Allows use of unmodifiable classes as keys, using legacy module or third-party code.
* PK需要被serializable才可以被存進去session
# 10 Relationships
**Relationships**
{%youtube I7PBM3BAOxI%}
> One to One Data Contained in Parent Table

**Ways to Associate Data**
* Value Types: Become single columns in containing Entity’s table.
* Embeddables: Add their attributes as columns in the containing Entity’s table.
* Entities: Become new tables which relate to a containing entity by a Join Column.
**Association Reciprocity**
**Unidirectional**(單向) - Association specified on one side of the relationship only.
* Doesn't retrieve data you won’t use.
* Should use Set collection type for most efficient SQL.
**Bidirectional**(雙向) - Association specified on both sides of the relationship. Use mappedBy on the containing Entity side.
* Access both sides of relationship with a single query.
* Hibernate recommends for `@OneToMany`, because it allows the foreign key constraint to exist only on the table of the contained object.
**Types of Entity Associations**
* **OneToOne**: Single Entity on each side of the relationship.
* **OneToMany** and **ManyToOne**: List of Entities on one side, single Entity on the other.
* ManyToMany: Lists of Entities on both sides.
We'll discuss these more in a later section!
# 11 Entity Relationships
**Entity Releationships**
{%youtube jUPoWNXzfms%}
> Association Types

**Unidirectional(單向)**
* Unidirectional 不能透過outfit知道有哪些人
You only need to specify the Entity on a single side of the relationship. For Example, this is the Person class showing a unidirectional `@OneToMany` relationship to Outfit.
```java
@Entity
public class Person {
@Id
@GeneratedValue
private Long id;
@OneToMany
private List<Outfit> outfits;
/* rest of class */
}
@Entity
public class Outfit {
@Id
@GeneratedValue
private Long id;
/* rest of class */
}
```
**Bidirectional(雙向)**
Both classes have a reference to each other. Here is a bidirectional OneToMany relationship showing that one person has many outfits, and each outfit has one person.
* Biddirectional可以透過outfit得知有哪些人
* oneToMany 人有很多衣服,但是在衣服方面就變成ManyToOne很多衣服針對一個人
```java
@Entity
public class Person {
@Id
@GeneratedValue
private Long id;
// person是Outfit屬性的名稱
@OneToMany(mappedBy = "person")
private List<Outfit> outfits;
/* rest of class */
}
@Entity
public class Outfit {
@Id
@GeneratedValue
private Long id;
@ManyToOne
private Person person;
/* rest of class */
}
```
**@JoinTable**
* ManyToMany一定要使用JoinTable
Many associations can be stored in a single `@JoinColumn` on one of the two entity tables, but you may also elect to store the relationship in a table designated for that purpose. `@ManyToMany` relationships must use a Join Table, and will automatically create one even if not specified.
To control the name of the table and its columns, you can use the` @JoinColumn` annotation.
```java
@Entity
public class Person {
@Id
@GeneratedValue
private Long id;
@ManyToMany
@JoinTable(
name = "person_outfit",
joinColumns = { @JoinColumn(name = "person_id")},
inverseJoinColumns = { @JoinColumn(name = "outfit_id")}
)
private List<Outfit> outfits;
/* rest of class */
}
```
**@ElementCollection**
You can use the `@ElementCollection` annotation to denote an association between a single Entity and a list of values that are not themselves Entities. This annotation lets you persist Lists of Embeddables or enums, for example. These embeddables will be stored in a separate table, along with the id of the Entity in which they are contained.
```java
@Entity
public class Person {
@Id
@GeneratedValue
private Long id;
@ElementCollection
private List<Outfit> outfits;
/* rest of class */
}
@Embeddable
public class Outfit {
private String hat;
private String gloves;
private String shoes;
private String legs;
private String top;
}
```
**Additional Resources**
* [Hibernate User Guide on Associations](https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#associations)
==ShannonNote==
* Unidirectional
* 只有在one(person)的那一方寫OneToMany,在many(outfit)的地方增加@Embeddable標誌
* person可以找到outfit但是outfit無法找到人
* Bidirectional
* 在one的那一方寫OneToMany, 在many的地方寫ManyToOne這樣就可以透過outfig去找到person
* @JoinTable
* 可以看補充05的多對多
* ElementCollection可以使用的形情
* One Entity to Many Values
* One Entity to Many Embeddables
# 12 Single Table Inheritance
{%youtube GOaxQvmx7Hw%}
**Inheritance**
Inheritance is a way to share data and associations across multiple related classes. This is an example of sharing the association from `Person` to `Outfit` with another class by creating a `Humanoid` parent class.
```java
@Entity
public abstract class Humanoid {
@Id
@GeneratedValue
Long id;
@OneToMany(mappedBy = "humanoid")
List<Outfit> outfits;
/* getters and setters */
}
@Entity
public class Person extends Humanoid {
@Type(type="nstring")
private String name;
private int age;
@Column(name="composer", length=512)
private String favoriteComposer;
/* getters and setters */
}
@Entity
public class CreepyDepartmentStoreMannequin extends Humanoid {
private boolean hasAHead;
private MannequinShape mannequinShape;
enum MannequinShape {
LITHE, MUSCULUR, UNASSUMING;
}
/* getters and setters */
}
```
Single Table Inheritance
The default inheritance strategy used by Hibernate is Single Table inheritance. All the fields of the parent and children classes are stored in the same table. Allows the fastest polymorphic(多樣態的) queries because no tables need to be joined to access all subclasses. Cannot support Not Null column constraints because columns must be able to contain null for sibling(兄弟姊妹) classes.
Polymorphic Query
A query for the parent class that returns elements of all subclass types.
> Single Table Inheritance

==ShannonNote==
> 今天會用到繼承的原因
* 首先我們知道person會有oneToMany對outfit,可是今天多了一個Mannequin(假人模特),他應該也要有多件outfit,但在outfit class裡面只有一個ManyToOne的person,因此我們才需要一個父類別,person跟mannequin繼承這個父類別,outfit去把ManyToOne的部分改成該父類別即可。
* the DTYPE column is used as a discriminator, storing the associated subclass name.
# 13 Other Inheritance Strategies
**Other Inheritance Strategies**
{%youtube m1yj6qbmEuQ%}
You can specify other inheritance strategies using the `@Inheritance` annotation on the parent class. The valid choices are `InheritanceType.SINGLE_TABLE`, `InheritanceType.JOINED`, and `InheritanceType.TABLE_PER_CLASS`.
```java
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public class Humanoid{
@Id
@GeneratedValue
Long id;
@OneToMany(mappedBy="humanoid")
List<Outfit> outfits;
//getters and setters
}
```
**JOINED**
Creates a table for the parent class and each subclass. The subclass tables only have fields unique to their class. Supports polymorphic queries by UNIONing subclass tables. Uses the least space of the solutions that allow Not Null columns.
**TABLE_PER_CLASS**
Creates a table for the parent class and each subclass. The subclass tables have all fields from the parent class as well as fields unique to their class. Supports polymorphic queries by UNIONing subclass tables, but does not require any UNION to access superclass fields on non-polymorphic queries.
**Mapped Superclass**
This is selected by using the `@MappedSuperclass` annotation on the parent class instead of `@Entity`. It creates a table per class just like TABLE_PER_CLASS, but there is no superclass table. It does not support polymorphic queries, but never requires UNIONS to query subclasses.
> Joined and Table Per Class Inheritance Strategies

**Additional Resources**
* [Hibernate documentation on Inheritance](https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#entity-inheritance)
---
==請看補充07==
# 14 Entities Exercise2
**Delivering Plants**
Our flower store is expanding! We now want to be able to deliver bushes in addition to flowers, so we need to update our program to support both shrubbery(灌木) and flowers.
Create a new parent class called `Plant` that contains the shared attributes of `name`, `price`, and `id`. Turn `Flower` into a subclass of `Plant` that just has the attribute `color`. Create a new class called `Shrub` and add attributes for `height` and `width`. We want to keep using our table ‘plant’ to store all the shared data, but our flowers and shrubs should have separate tables for their unique fields, so make any changes necessary for this to happen.
We also want to update our `Delivery` class so that it is associated with our plants. Modify `Delivery` so that it includes a list of all the `Flowers` and `Shrubs` to be included in the delivery. Make this association bidirectional, and store the association in the ‘plant’ table in a column called ‘delivery_id’.
Make sure to add and update any relevant getter and setter methods.
# 15 Solution: Entities Exercise2
`Delivering Plants Solution`
Great job! We expanded out our first exercise to create an even better delivery service. Let’s look at one way to implement these solutions.
**Plant.java**
```java
// Uses InheritanceType.JOINED to store shared fields in 'plant' and unique fields
// in subclass tables
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Plant {
@Id
@GeneratedValue
private Long id;
@Nationalized // should use @Nationalized instead of @Type=nstring
private String name;
@Column(precision=12, scale=4)
private BigDecimal price; // BigDecimal is the standard Java class for currency math
@ManyToOne //many plants can belong to one delivery
@JoinColumn(name = "delivery_id") //map the join column in the plant table
private Delivery delivery;
/* getters and setters*/
}
```
**Flower.java**
```java
@Entity
public class Flower extends Plant {
private String color;
/* getters and setters*/
}
```
**Shrub.java**
```java
@Entity
public class Shrub extends Plant {
private int heightCm; //any reasonable unit of measurement is fine
private int widthCm;
/* getters and setters*/
}
```
**Delivery.java**
```java
@Entity
public class Delivery {
@Id
@GeneratedValue
private Long id;
@Nationalized
private String name;
@Column(name = "address_full", length = 500)
private String address;
private LocalDateTime deliveryTime;
@Type(type = "yes_no")
private Boolean completed;
//make sure to specify mappedBy. Lazy fetch optional,
// but often a good idea for collection attributes
@OneToMany(fetch = FetchType.LAZY, mappedBy = "delivery")
private List<Plant> plants;
/* getters and setters */
}
```
# 16 Entities in Multitier Architecture
{%youtube RvxKl94xqhw%}
Entity Role in Multitier Architecture
Entities belong in the Data layer, as their primary role is bridging the communication between our Application layer and the database. They also serve as components of business logic, making them relevant components in our controller and service layers.
The Application layer should not communicate with the database, and the Data layer should not execute business logic.
> Entity Visibility in Multitier Architecture(多層架構)

**Multitier Architecture Advantages**
**Maintenance**
* Centralizes(集中) access(訪問) to your data source
* Reduces time needed to make changes to Entity interactions
* Reduces amount of code each developer needs to understand
**Performance**
* Allows application layers to easily be separated into modules
* Reduces application size
* Enables scaling of independent components
* Supports future architecture deployment
**Security**
* Able to secure each tier with different permissions
* Reduces redundant(unnecessary) authentication in other tiers
* Data sanitization(清潔過濾) and validation boundaries
// sanitization: the act or process of making something completely clean and free from
# 17 Data Conversion
**Data Conversion**
{%youtube wpA1ahs1IF8%}
**Data Transfer Objects (DTOs)**
Data structures designed to represent the needs of the front end.
**DTO Summary**
* Simplify and document interaction between front end and Controller.
* Conceal(hide) database structures.
* Limit the amount of data exchanged.
* Customize display data to meet the needs of the front end.
**JSONView Demo**
{%youtube OCLe0VHd208%}
> Differences between DTO and `@JSONView`

**JSONView Annotations**
Annotation that filters which Entity data is visible to the Presentation layer.
**`@JSONView` Summary**
* Quickly specify which parts of Entities should be visible to which consumer.
* Often a simple choice when controlling full stack.
* Not as helpful when you need to combine data from multiple Entities.
* Can require Entity updates if front end needs change.
* Often grouped together in a Views class, containing interfaces such as ‘Public’, ‘Private’, or interfaces named for specific endpoint recipients.
# 18 Entities Exercise 3
`Plant DTO`
We want to make a REST endpoint that allows users to retrieve the price for a plant with a specific name, but we don’t want to show them ids or any information about the Delivery that plant is scheduled for. For this assignment, we’ll solve the problem twice: once using a DTO and once using the `@JSONView` annotation.
Let’s add a shell Service and Controller to demonstrate how to use DTOs and `@JSONView`. Create a class called PlantService that returns a Plant instance:
```java
@Service
public class PlantService {
public Plant getPlantByName(String name){
return new Plant();
}
}
```
Then create a class called PlantController that offers two methods. One of these methods will return a PlantDTO that includes only the name and price. The other method should return a Plant Entity instance. Both the method and entity should be modified so that only the name and price fields from the Entity are returned. Here is the starter code for the PlantController.java:
```java
@RestController
@RequestMapping("/plant")
public class PlantController {
@Autowired
private PlantService plantService;
public PlantDTO getPlantDTO(String name){
Plant plant = plantService.getPlantByName(name);
return null;
}
public Plant getFilteredPlant(String name){
return plantService.getPlantByName(name);
}
}
```
# 19 Solution: Entites Exercise3
**`PlantDTO` Solution**
Great job! Our plant delivery system is really taking off! We can now convert our data into the format used by our recipients and have isolated those changes from our database format.
> PlantController.java
```java
@RestController
@RequestMapping("/plant")
public class PlantController {
@Autowired
private PlantService plantService;
public PlantDTO getPlantDTO(String name){
return convertPlantToPlantDTO(plantService.getPlantByName(name));
}
@JsonView(Views.Public.class)
public Plant getFilteredPlant(String name){
return plantService.getPlantByName(name);
}
private PlantDTO convertPlantToPlantDTO(Plant plant){
PlantDTO plantDTO = new PlantDTO();
BeanUtils.copyProperties(plant, plantDTO);
return plantDTO;
}
}
```
> Views.java
```java
public class Views {
public interface Public {}
}
```
> Plant.java
```java
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Plant {
@Id
@GeneratedValue
private Long id;
@JsonView(Views.Public.class)
@Nationalized // should use @Nationalized instead of @Type=nstring
private String name;
@JsonView(Views.Public.class)
@Column(precision=12, scale=4)
private BigDecimal price; // BigDecimal is the standard Java class for currency math
@ManyToOne //many plants can belong to one delivery
@JoinColumn(name = "delivery_id") //map the join column in the plant table
private Delivery delivery;
/* getters and setters*/
}
```
> PlantDTO.java
```java
public class PlantDTO {
private String name;
private BigDecimal price;
/* getters and setters */
}
```
> BeanUtils.copyProperties 在補充11
==ShannonNote==
可以參考github裡面以下資料夾
https://github.com/ShannonHung/Udacity-Lesson3-Part2.git
* Plant
* Plant.java
* Views.java
* PlantService
* PlantService.java
* PlantController
* PlantController.java
# 20 Data in Multitier Architecture
{%youtube lciXYPTeqeQ%}
**Lesson Outline**
1. Value vs. Entity types
2. BasicTypes in Java and JDBC
3. Identifiers
4. Relationships
5. Inheritance
**Glossary(詞彙表)**
* Multitier Architecture
Refers to a form of design that separates various functions of the application into their own layers.
* Java Persistence API (JPA)
A specification describing how to manage relational data.
* Hibernate
An *implementation of the JPA Specification*. [You can access Hibernate’s documentation page here.](https://hibernate.org/orm/)
* POJO or "Plain Old Java Object"
A Java object that contains data, but no methods to describe behavior.
* Entity Types
Java classes that describe a collection of data.
1. Contain Data only, no behavior
2. Represented by a table in the database
* Value Types
The data inside an Entity.
1. Primitives like int, boolean, char
2. Classes that only represent a single piece of data, like BigInteger or LocalDate
3. Represented by a column in the database
* Basic Types
Basic Types map a single database column to a single, non-aggregated Java type.
* Serialization
Transforming your data into a format that can be stored and reconstructed later.
* First Normal form
Each attribute of a table contains only atomic values.
* Atomic
Representing a single piece of data; indivisible不可分割.
* Embeddables
Add their attributes as columns in the containing Entity’s table.
* Entities
Become new tables which relate to a containing entity by a Join Column.
* Unidirectional
Association specified on one side of the relationship only.只有一邊一對多,另外一個entity沒有寫任何關係
1. Doesn't retrieve data you won’t use.
2. Should use Set collection type for most efficient SQL.
* Bidirectional
Association specified on both sides of the relationship. Use mappedBy on the containing Entity side.
1. Access both sides of relationship with a single query.
2. Hibernate recommends for @OneToMany, because it allows the foreign key constraint to exist only on the table of the contained object.
* OneToOne
Single Entity on each side of the relationship.
* OneToMany and ManyToOne
List of Entities on one side, single Entity on the other.
* ManyToMany
Lists of Entities on both sides.
* Inheritance
Inheritance is a way to share data and associations across multiple related classes.
* Single Table Inheritance
The default inheritance strategy used by Hibernate. All the fields of the parent and children classes are stored in the same table. Allows the fastest polymorphic queries because no tables need to be joined to access all subclasses. Cannot support Not Null column constraints because columns must be able to contain null for sibling classes.
* Polymorphic Query
A query for the parent class that returns elements of all subclass types.
* Joined Inheritance
Creates a table for the parent class and each subclass. The subclass tables only have fields unique to their class. Supports polymorphic queries by UNIONing subclass tables. Uses the least space of the solutions that allow Not Null columns.
* Table Per Class Inheritance
Creates a table for the parent class and each subclass. *The subclass tables have all fields from the parent class* as well as fields unique to their class. Supports polymorphic queries by UNIONing subclass tables, but does not require any UNION to access superclass fields on non-polymorphic queries.
* Mapped Superclass
This is selected by using the `@MappedSuperclass` annotation on the parent class instead of @Entity. It creates a table per class just like TABLE_PER_CLASS, but there is no superclass table. It does not support polymorphic queries, but never requires UNIONS to query subclasses.
* Data Transfer Objects (DTOs)
Data structures designed to represent the needs of the front end.
* JSONView Annotations
Annotation that filters which Entity data is visible to the Presentation layer.
# 補充01 : Hibernate ORM
來源:https://hibernate.org/orm/
1. Object/Relational Mapping
* Hibernate ORM可以讓使用者更簡單地去寫applications,然後裡面的data可以在程式非運行階段繼續存在, Hibernate最為一個ORM Framework可以保持Data的持久性當這個Data應用在關聯資料表的時候。
2. JPA Provider
* 除了本地的API, Hibernate也有實作JPA的規範。所以不管在哪個環境,都可以被easily used 去支援JPA including Java SE, Java EE, Enteriprise OSGi containers, etc.
3. Idiomatic(慣用代碼的) persistence
* 他跟一般java用法差不多,像是可以繼承, 多型, association, composition又或是collections frameworks. 並且她不需要透過interface又是base classes來persistent classes. 能夠使任何class或是data持久化。
4. High Performance
* Hibernate支援lazy initialization, 有很多很讚的策略跟optimistic locking with
> 補充:Lazy Initialization https://openhome.cc/Gossip/HibernateGossip/LazyInitialization.html
5. Scalability (擴展性)
* Hibernate旨在在應用程序服務器群集中工作並提供高度可擴展的體系結構。Hibernate在任何環境下均可很好地擴展
6. Reliable
* Hibernate以其出色的穩定性和質量而著稱,並通過成千上萬的Java開發人員的接受和使用證明。
7. Extensibility
* Hibernate是高度可配置和可擴展的。
# 補充02: Hibernate - Mapping types
來源: https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#mapping-types
Hibernate能夠懂java跟JDBC的application data. Hibernate type能夠去讀寫Data from the database.
* Type
* 實現org.hibernate.type.Type的interface.
* 這種Hibernate類型還描述了Java類型的各種行為方面,例如如何檢查是否相等,如何克隆值等。
* Usage of the word type
* Hibernate type不是java type就是SQK data type
* 他提供了information about mapping a java type to an sql type as well as how to persist and fetch(接sth回來) a given java type to and from a relational database.
> Example1. A simple table and domain model
```sql
create table Contact (
id integer not null,
first varchar(255),
last varchar(255),
middle varchar varchar(255),
notes varchar(255),
starred boolean not null,
website varchar(255),
primary key (id)
)
```
```java
@Entity(name="Contact")
public static class Contact{
@Id
private Integer id;
private Name name;
private String notes;
private URL website;
private boolean starred;
//Getter and setter are omitted(忽略) for brevity(簡短)
}
@Embeddable
public class Name{
private String first;
private String middle;
private String last;
//Getter and setter are omitted(忽略) for brevity(簡短)
}
```
In the broadest sense(廣義), Hibernate 分為兩大類
* Value types
* Entity types
**Value types**
* 他被entity所擁有,而且他只是一個沒有被定義他lifecycle的小Data
* 所有的entity狀態 都是由value type所組成
* 他又被分三個子類
* Basic Types
* 在上面的contact裡面除了name之外,其他的類別都是basic type,簡單來說就是一般的string, int, double, etc
* Embeddable(可嵌入的) types
* 上面的name就是一種embedded type
* Collection types
* 像是跟list有關的屬性
**Entity Types**
* Contact class本身就是Entity Types
# 補充03: Generated Identifier Values
Hibernate支援identifier value可以產生不同的types. 但是JPA只生產integer type給identifier。
* 自動產生identifier value是透過`javax.persistence.GeneratedValue`標註
* identifier value如何產生的是透過`javax.persistence.GenerationType`
* [AUTO](https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#identifiers-generators-auto)
* Hibernate should choose an appropriate generation strategy.
* [IDENTITY](https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#identifiers-generators-identity)
* 資料庫IDENTITIY cloumns會被用來使用給primary key value generation.
* [SEQUENCE](https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#identifiers-generators-sequence)
* 資料庫sequence應該被用來使用去抓取primary key value
* [TABLE](https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#identifiers-generators-table)
* 資料庫table應該被使用來抓取primary key
# 補充03: @Nationalized用法
To map a specific attribute to a nationalized variant data type, Hibernate defines the @Nationalized annotation.
簡單來說就是他可以協助你把一些奇怪的type像是NCLOB轉成你想要的型態但型態是有限定的,像是string, char[]等等
## NCLOB轉換
> `NCLOB` SQL
* 裡面的nclob type 要去mapping到一個nationalized的type
```sql
CREATE TABLE Product (
id INTEGER NOT NULL ,
name VARCHAR(255) ,
warranty nclob ,
PRIMARY KEY ( id )
)
```
> `NCLOB` mapped to `java.sql.NClob`
```java
@Entity(name = "Product")
public static class Product {
@Id
private Integer id;
private String name;
@Lob
@Nationalized
// Clob also works, because NClob extends Clob.
// The database type is still NCLOB either way and handled as such.
private NClob warranty;
//Getters and setters are omitted for brevity
}
```
**如果想要setWarranty()**
* create a `NClob` instance using the `NClobProxy` Hibernate utiltiy.
```java
final Product product = new Product();
product.setId(1);
product.setName("Mobile phone");
String warranty = "My product warranty";
product.setWarranty( NClobProxy.generateProxy(warranty));
entityManager.persist(product);
```
# 補充04: Override equal() and hashCode()
參考:
- https://blog.csdn.net/javazejian/article/details/51348320
**Equals()重寫特性與規則**
* 自反性: 自己equal自己一定是true。`x.equals(x) == true`
* 對稱性: 如果`x.equals(x) == true` 那就代表 `y.equals(x) == ture`。
* 傳遞姓: 三個object, x, y ,z, 如果`y.equals(x)==true`且`y.equals(x) == true`那麼`x.equals(x)`一定也是true。
* 一致姓: 假設object的equals()沒有被修改,則多次使用`x.equals(y)`始終返回相同的值。
* `x.equals(null)` 應該返回false
**HashCode()的規則**
* 在java應用程序執行時間,如果再equals方法比較中所用的訊息沒有被修改,那麼在同一個object上多次使用hashcode方法時必須一致的反為相同的整數,如果多次執行同一個應用部要求整數必須相同。
* 如果兩個對象通過equals方法是相同的那麼兩個對象調用hashcode方法必須返回相同的整數。
* 如果兩個對象通過equals()不相等,不要求兩個對象調用hashcode方法必須返頹不同的整數。
**instanceof**
他是java的一個二元操作符號,類似 `==`, `<`, `>`。instanceof的作用是測試他左邊的object是否是她右邊class的instance,返回boolean的數據類型。
```java
@Override
public boolean equals(Object obj) {
if (obj instanceof Combination4BigCar) {
Combination4BigCar bc = (Combination4BigCar) obj;
return c.equals(bc.c) && count == bc.count;
}
return false;
}
```
## Documentation
- 參考https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#identifiers-composite
Composite identifiers correspond(equal) to one or more persistent attributes. Here are the ruls governing composite identifiers, ad defined by the JPA specification(documentation).
* The composite identifier mush be represented by a "primary key class" liek `PersonPK`.
* This class may be defined using the `javax.persistence.EmbeddedId` annotation, or defined using the `javax.persistence.IdClass` annotation.
* The primary key class must be public and mush have a public no-arg constructor.
* The primary key class must be serializable.
* The primary key myst define equals and hashCode methods, consistent with equality for the underlying database types to which the primary key is mapped.
### Composite identifiers with `@EmbeddedId`
參考: https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#identifiers-composite-aggregated
Modeling a composite identifier using an EmbeddedId simply means defining an embeddable to be a composition for the one or more attributes.
>Basic @EmbeddedId
```java
@Entity(name = "SystemUser")
public static class SystemUser {
@EmbeddedId
private PK pk;
private String name;
//Getters and setters are omitted for brevity
}
@Embeddable
public static class PK implements Serializable {
private String subsystem;
private String username;
public PK(String subsystem, String username) {
this.subsystem = subsystem;
this.username = username;
}
private PK() {
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
PK pk = (PK) o;
return Objects.equals( subsystem, pk.subsystem ) &&
Objects.equals( username, pk.username );
}
@Override
public int hashCode() {
return Objects.hash( subsystem, username );
}
}
```
As mentioned before, EmbeddedIds can even contain `@ManyToOne` attributes.
```java
@Entity(name = "SystemUser")
public static class SystemUser {
@EmbeddedId
private PK pk;
private String name;
//Getters and setters are omitted for brevity
}
@Entity(name = "Subsystem")
public static class Subsystem {
@Id
private String id;
private String description;
//Getters and setters are omitted for brevity
}
@Embeddable
public static class PK implements Serializable {
@ManyToOne(fetch = FetchType.LAZY)
private Subsystem subsystem;
private String username;
public PK(Subsystem subsystem, String username) {
this.subsystem = subsystem;
this.username = username;
}
private PK() {
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
PK pk = (PK) o;
return Objects.equals( subsystem, pk.subsystem ) &&
Objects.equals( username, pk.username );
}
@Override
public int hashCode() {
return Objects.hash( subsystem, username );
}
}
```
### IdClass
參考: https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#identifiers-composite-nonaggregated
Modeling a composite identifier using an IdClass differs from using an EmbeddedId in that the entity defines each individual attribute making up the composition. The IdClass simply acts as a "shadow".
> Basic @IdClass
```java
@Entity(name = "SystemUser")
//在這裡指定PK的class
@IdClass( PK.class )
public static class SystemUser {
@Id
private String subsystem;
@Id
private String username;
private String name;
public PK getId() {
return new PK(
subsystem,
username
);
}
public void setId(PK id) {
this.subsystem = id.getSubsystem();
this.username = id.getUsername();
}
//Getters and setters are omitted for brevity
}
public static class PK implements Serializable {
private String subsystem;
private String username;
public PK(String subsystem, String username) {
this.subsystem = subsystem;
this.username = username;
}
private PK() {
}
//Getters and setters are omitted for brevity
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
PK pk = (PK) o;
return Objects.equals( subsystem, pk.subsystem ) &&
Objects.equals( username, pk.username );
}
@Override
public int hashCode() {
return Objects.hash( subsystem, username );
}
}
```
# 補充05: Associations
參考:https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#associations
- 中文:https://codertw.com/%E8%B3%87%E6%96%99%E5%BA%AB/128556/
Associations describe how two or more entities form a relatioship based on a database joining semantics(the study of learning languague).
## @ManyToOne
@ManyToOne is the most commom association, having a direct equivalent in the relational database as well (e.g. foreign key), and so it establishes a relationship between a child entity and a parent.
```java
@Entity(name = "Person")
public static class Person{
@Id
@GeneratedValue
private Long id;
//Getter and Setter
}
@Entity(name="Phone")
public static class Phone{
@Id
@GeneratedValue
private Long id;
@Column(name="name")
private String number;
@ManyToOne
@JoinColumn(name="person_id"
foreignKey=@ForeignKey(name="Person_ID_FK"))
private Person person;
//getter and setter
}
```
> java in sql means
```sql
CREATE TABLE Person(
id BIGINT NOT NULL,
PRIMARY KEY(id)
)
CREATE TABLE Phone(
id BIGINT NOT NULL,
number VARCHAR(255),
person_id BIGINT,
PRIMARY KEY(id)
)
ALTER TABLE Phone
ADD CONSTRAINT PERSON_ID_FK
FOREIGN KEY (person_id) REFERENCES Person
```
* `ALTER TABLE "TableName"` 也可以被用來作其他的改變,例如改變主鍵定義
* `ADD CONSTRAINT PERSON_ID_FK` 表示新增欄位`person_id_fk`
* `FOREIGN KEY (person_id) REFERENCES Person` 表示把table Phone的person_id欄位reference到Person
* Once the @ManyToOne association is set, Hibernate will set the associated database foreign key column.
> `@ManyToOne` association lifecycle
```java
Person person = new Person();
entityManager.persist(person);
Phone phone = new Phone("123-456-7890");
phone.setPerson(null);
```
```sql
INSERT INTO Person(id) VALUES(1)
INSERT INTO Phone(number, person_id, id) VALUES('1234-456-789', 1, 2)
UPDATE Phone SET number = '123-456-7890', person_id = NULL WHERE id = 2
```
## OneToMany
The @OneToMany association links a parent entity with one or more child entities. It is bidirectional and the application developer can navigate this relationship from both ends.
If you use OneToMany, Hibernate resorts(採取) to using a link table between the two joining entities.
> Example @OneToMany association
```java
@Entity(name = "Person")
public static class Person {
@Id
@GeneratedValue
private Long id;
//@OneToMany設定了cascade=CascadeType.ALL,這時刪除一端時不會丟擲異常,多端外來鍵被設定為null。
@OneToMany(cascade=CascadeType.All, orphanRemoval=true)
private List<Phone> phones = new ArrayList<>();
//Getters and setters are omitted for brevity
}
@Entity(name = "Phone")
public static class Phone {
@Id
@GeneratedValue
private Long id;
@Column(name = "`number`")
private String number;
//Getters and setters are omitted for brevity
}
```
## ManyToMany
參考: https://openhome.cc/Gossip/EJB3Gossip/ManyToMany.html

可以使用ManyToMany標註,使用如下
```java
@Entity
@Table(name="T_USER")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="USER_ID")
private Long id;
private String name;
private Long age;
@ManyToMany(cascade=CascadeType.ALL)
@JoinTable(
name="T_USER_SERVER",
joinColumns={@JoinColumn(name="USER_FK")},
inverseJoinColumns={@JoinColumn(name="SERVER_FK")}
)
private Set<Server> servers;
// 以下為 Getter、Setter
...
}
```
* 你可以發現其中@JoinTable中的name是中介的表格名稱,並且設定對應的欄位名稱
> Server可以如下設定
```java
@Entity
@Table(name="T_SERVER")
public class Server {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="SERVER_ID")
private Long id;
private String address;
@ManyToMany(cascade=CascadeType.ALL, mappedBy="servers")
private Set<User> users;
// 以下是 Getter、Setter
...
}
```
* 透過mappedBy屬性設定雙向關聯
# 補充06: Embedded & Embeddable
參考: https://www.jianshu.com/p/35dcdc36fb6c
Class Employee有一個address屬性,address應該要有city, street兩個屬性,一班寫法直接在employee class中寫
```java
private String city;
private String street;
```
但是透過Embeddable可以用一個Address class來代替上述的寫法,因此可以在Employee類只要這樣寫
```java
private Address address;
```
> sql
```sql
CREATE TABLE `t_employee` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`city` varchar(255) DEFAULT NULL,
`street` varchar(255) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
```
> Address class
```java
@Embeddable
public class Address {
private String city;
private String street;
//getter and setter
}
```
> Employee class
```java
@Entity
@Table(name = "t_employee")
public class Employee {
@Id
@GeneratedValue
private Long id;
private String name;
@Embedded
private Address address;
//getter and setter
}
```
# 補充07: Inheritance
他有分四大類
* [mappedSuperclass](https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#entity-inheritance-mapped-superclass)
* 透過@MappedSuperClass在父類別裡面instead of @Entity,子類別有幾個就會產出幾個table,沒有reference也沒有父類別
* [Single table](https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#entity-inheritance-single-table)
* 就是12的例子,需要一個父類別,不管有幾個子類別,只會產生一個table
* [Joined table](https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#entity-inheritance-joined-table)
* 父類別新增`@Inheritance(strategy = InheritanceType.JOINED)`
* 子類別新增`@PrimaryKeyJoinColumn(name = "account_id")`
* 會產生父類別跟子類別的table並且會做reference
* [Table per class](https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#entity-inheritance-table-per-class)
* 父類別新增`@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)`
* 會產生父類別table跟子類別table,子類別table裡面的屬性已經包含父類別的,但是子類別每有跟任何table reference
## Inheritance Mapping Strategies
1. Single Table:
* Store all subclasses in one table. Requires nullable columns for subclass fields.
2. Joined Table:
* One table per entity, including parent. Parent fields not duplicated(copy) in subclass tables.
3. Table Per Class:
* One table per entity, with parent fields duplicated in subclass table.
4. Mapped Surperclass:
* One table per subclass, no parent class table. Does not support polumorphic queries.
# 補充08: 關於fetch = FetchType.LAZY 跟 EAGER
參考: https://blog.csdn.net/u010082453/article/details/43339031
如果採用FetchType.LAZY的話代表不會立即加載物件的相關訊息,只有等到要顯示或是用到時才會載入,相對的如果使用Fetch.EAGER的話會立即下載物件的相關訊息,像是姓名這類常需要顯示的訊息。
# 補充09: DTO Data Transfer Object
參考:
- Data Transfer Object使用心得及時機https://www.petekcchen.com/2010/12/how-to-use-data-transfer-object.html
在了解DTO之前,先了解何謂Business Object(BO),BO是一個帶有資寮及雌作行為的物件
> Example of BO
```java
public class UserInfo
{
public string Account { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string PostCode { get; set; }
public string Address { get; set; }
public DateTime LastModifiedTime { get; set; }
public DateTime CreatedTime { get; set; }
public string GetFullName()
{
return string.Concat(this.FirstName, this.LastName);
}
public string GetFullAddress()
{
return string.Concat(this.PostCode, this.Address);
}
}
```
> 引述Microsoft .NET: Architecting Applications for the Enterprise
A data-transfer object is a sort of value object-namely, a mere container of data with no attached behavior.
> 引述Patterns of Enterprise Application Archetecture
A object that carries data between processes in order to reduce the number of method calls.
根據上面的字面定義來說,DTO是一個帶有資料的物件但是沒有人和操作行為
> Example of DTO
```java
public class UserInfoDto
{
public string Account { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string PostCode { get; set; }
public string Address { get; set; }
public DateTime LastModifiedTime { get; set; }
}
```
## DTO 特性
* DTO為多個BO的子集
* 一個BO可能有多個DTO子集合
* DTO僅包含屬性值無任何操作行為
* 減少暴露過多資訊給client code僅提供client code會使用到的資料
* 這樣帶來的好處有:
1. 依據現有的類代碼,即可方便的構造出DTO對象,而無需重新進行分析。
2. 減少請求次數,大大提高效率。
3. 按需組織DTO對象,頁面需要的欄位我才組織,不需要的我不組織,可以避免傳輸整個表的欄位,一定程度上提高了安全性。
原文網址:https://kknews.cc/code/9zkxb6l.html
> 原本取得資料的方式

> DTO取得資料的方式

## 使用時機
* 想要縮短Presentation Layer呼叫Service Layer時所傳遞的參數數量及次數時
# 補充10: Spring MVC @JsonView使用詳解
參考: https://www.jianshu.com/p/633d83dd303b
## 基本用法
`@Json` can be used to filter serialize the attribute of objects. You can choose which you want to serilalize. First we define a `View` class裡面包含要序列劃的字段定義,暫時稱Summary(摘要)。
> 這裡也可以將`View`class理解為一組"標示",而`summary`就是其中一組"標示"。
```java
public class View{
interface Summary{}
}
```
然後我們定義Bean類: `User`
* 可以看到`@JsonView`使用上加在屬性指定一個"標示"像是Summary
* Summary指定給id, firstname, lastname三個屬性,因此當我們使用@JsonView序列化User對象的時候,只會序列化三個屬性,可以影藏一些不想序列化的字段屬性。
```java
public class User {
@JsonView(View.Summary.class)
private Long id;
@JsonView(View.Summary.class)
private String firstname;
@JsonView(View.Summary.class)
private String lastname;
private String email;
private String address;
private String postalCode;
private String city;
private String country;
}
```
> Controller
> * 在contoller中指定JsonView
> * 當訪問`/user`會得到序列化的屬性
```java
@RestController
public class UserRestController{
@Autowired
private UserService userService;
@RequestMapping("/user")
@JsonView(View.Summary.class)
public List<User> getUsers(){
return userService.listUsers();
}
}
```
> Json
```json
[
{ "id" : 1, "firstname" : "Brian", "lastname" : "Clozel" },
{ "id" : 2, "firstname" : "Stéphane", "lastname" : "Nicoll" },
{ "id" : 3, "firstname" : "Rossen", "lastname" : "Stoyanchev" }
]
```
## udacity用法
可以參考本章 18, 19
# 補充11: BeanUtils.copyProperties 用法
> BeanUtils.copyProperties
```java
public static void copyProperties(java.lang.Object dest, java.lang.Object orig){
throws java.lang.IllegalAccessException, java.lang.reflect.InvocationTargetException;
}
```
* JavaBean處理導致大量set get程式碼堆積稱家程式碼長度跟閱讀難度該怎麼辦?
* BeanUtils利用反射機制對JavaBean的屬性進行處理
* `copyProperties(Object A, Object B)`簡單來說就是把B裡面的屬性值複製到A這個物件,如果A和B存在名稱不同的屬性BeanUtils不對這些屬性進行處理,需要工程師手動處理
* 結論: 我們可以把B物件複製屬性到A物件,不管物件有多少個屬性100個1000個都不需慢慢get, set進去進行複製! 但BeanUtils的成本額貴,時間超ㄍㄨ