專題大天地
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Help
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    1
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 01.4-SpringBoot basics-Lesson4: Spring MVC and Thymeleaf ###### tags: `Udacity` [ToC] # 1.Spring MVC and Thymeleaf {%youtube gA3tNZ05vQs%} **下圖為Spring MVC and Thymeleaf** ![](https://i.imgur.com/9yKCqH7.png) - Lesson Outline - MVC and You: We introduce the model-view-controller pattern and discuss how Spring MVC adapts it for use on the web. - HTML Templates and Thymeleaf: We look at how Thymeleaf's HTML templates work and how we can populate them with data usign Spring controllers. - Connecting Controllers to Templates: We dive deeper into the relationship between controllers and templates to see how to bind data from a web form to a controller method. ==Shannon Note After Watching Video== >這堂課會學到的東西 >* 如何把Spring MVC裡面Controller的部分連接到Thymeleaf,這樣就可以在前端跟後端之間 bind data。 * Thymeleaf對我來講就是一種HTML的引擎,可以用來定義我們的web page,然後把數據填入 >* Thymeleaf對創建dynamic websites的重要性,然後如何實現UI的行為,像是Conditional Rendering(條件渲染)或是User Data Submission >* 如何使用Spring MVC controller 組件去動態選擇Thymeleaf templates to render根據user的requests. >* Spring MVC針對特殊的request data types像是file uploads的處理方式。 >* 透過`<form input>`跟dynamic spring back data做出一個user-facing web page > >補充資料: Conditional Rendering https://testudy.cc/tech/2016/12/19/react-8-conditional-rendering.html # 2.Developing Web Sites from the Back-End {%youtube qnkzSh2Bc9A%} **下圖為The Relationship Between Spring MVC and the Client** ![](https://i.imgur.com/mdKoJ5B.png) In a web application, there are two components: the client that sends HTTP requests, and the server, which sends HTTP responses back. In the case of a web browser client, the responses the server sends need to be in the format of HTML, the document language of the web. The HTML that is sent to the client both defines the data that the user sees, as well as the actions a user can take - things like buttons, links, and input forms are all part of what the server is responsible for generating. ==Shannon Note== >1. Web application有兩個組件 >- client: 負責發送HTTP request - request只是一個二位元的檔案binary document,一連串的0跟1組成 >- server: 負責回傳HTTP response - 在browser裡面,要透過html的格式來作回應 - 回應的HTML可以讓user做出一些行為像是button, links, input form之類的 This process of generating an entire UI from HTML would be tedious if we had to do it by hand. Luckily, we don't have to - Thymeleaf is an HTML template engine that, when used with Spring MVC, can simplify things greatly. ==Shannon Note== >1. 做UI幹他媽的繁瑣,但我們有Thymeleaf!! 一個HTML template引擎,而且還搭配Spring MVC使用,可以大大的簡化繁瑣的事情!! HTML templates are essentially just HTML files with special tags and attributes that can be combined with a data model by a template engine like Thymeleaf to generate fully functional HTML documents. Spring MVC provides a standard way to choose a template and supply the necessary data model when a request comes in, which allows for a truly dynamic user experience. ==Shannon Note== >1. 可以透過Thymeleaf來產生功能俱全的HTML Template,Spring MVC提供一個標準的方式去選擇模板,然後如果一個request來時,可以套用必要的data model,來給使用者一個真實的動態體驗。 **Key Terms** * `GET` Request: an HTTP request for data at a specific URL. This type of request cannot include any additional data. * `POST` Request: and HTTP request that usually represents "posting" new data to the server. This is a common catch-all request method used for many data-bearing requests to the server. * Dynamic: Something that is dynamic changes in response to external stimuli. In the case of HTML templates, dynamic sections of the template are ones that can be replaced or configured with data on-demand. * Static: Something that is static does not change. In the case of HTML templates, static sections of the template are the ones that cannot be changed and will be the same no matter what data is used with the template. * MVC: Model-View-Controller, a design pattern that emphasizes the separation of application components into those three categories or layers for more-structured user-facing application development. ==Shannon Note After Watching Video== >1. 當一個client想要看一個server,他會寄Http request給那個Server的address and port,像是你輸入網址然後enter,他會發送一個`Get`的HTTP method。當Server收到後,會回傳一個request HTML data。 > >2. 針對回傳的HTML Document我們需要知道要populate甚麼資料,舉例來說,我們要網路上開店,放上所有產品,讓client可以搜尋我們的庫存,所以submit一個search query,我們的application 可以選擇回傳一個valid results HTML給client。 > >3. 手動製造回應的HTML很難,因此才需要HTML template engine like Thymeleaf,它可以提供一個簡單的方式去定義可以動態填入資料且又可以在某些情況下重複使用的HTML pattern > >4. 如何結合Spring MVC? 1. 先develop html tempates 給users看 2. develop spring beans去處理client的actions,然後執行application 邏輯,然後再填入application data進去適當的template which is **rendered** as a view to the client browser > >* **render**的意思 * (1)to give something such as a service, a personal opinion or expression, or a performance of a song or poem, etc. to people: * (2) to put a first layer of plaster or cement on a wall # 3.Intuition {%youtube DJsfz_IaUzA%} There are three basic scenarios that comprise the majority of web-based user interaction flows. The first is when a user follows a link to our application from an external source, like a marketing email or google search. This kind of cold-call request means will always be a GET request, and our application's responsibility is to choose a response template (appropriate for the request URL - you don't want to send the register.html if the link the user clicked was for /shopping-cart!) and populate it with relevant application data. ==Shannon Note== >主要有三種基本方式去構成大多數基於Web的user交流流程 >1. user從外部的link(like email or google search, this way will be called ***Cold-call***)連接近來our application,是透過`Get`的方式去request。 > 當application收到請求之後,application負責去找要response的template並且裡面應該載入要回應的相關資料內容(通常也是回應一個URL,因為你不會想去寄送register.html) The second scenario is when a user navigates within our app, either by clicking a link or a button or performing some action we need to process on the server, like adding an item to their shopping cart. This case is very similar to the first, as it involves the server choosing a response template and populating it with data, but in this case, the action the user performs is completely up to us - since they're initiating the action from a web page we designed, only the actions we included in that design are available. We can use this to add additional data to requests at the template-level, for example by generating each "add item to cart" button to include the item's identifier in the request that is sent. ==Shannon Note== >2. 第二個情境: 當user到我們的app不管是透過連結或是點擊button又或是執行我們知道並且需要去處理的動作,我們可以自行訂要回應的內容,ex.在商品裡面,生成"add item to cart butoon",點下去的時候就會包含這個item的identifier在request裡面寄出去。 > >*define **identifier**: a set of numbers, letters, or symbols that is used to represent a piece of data or a process in a computer program. The final scenario is when the user submits completely custom data to our app using form input. This is again similar to the previous two, in that the exact shape of the form is something our template design determines, and that we still need to choose a template to send in response and the data we should use to populate this template. The main difference is that the request no longer includes "safe" data - when a user can enter any data that they'd like, our application is responsible for vetting and validating that data, showing the user an error if something goes wrong. These scenarios may seem simple, but they are the building blocks of web development. Regardless of the application, user interaction flows on the web are all built out of these basic building blocks. ==Shannon Note== >3. 第三種情境裡面,當user透過`form input`來傳送完整的custom data給我們的application,那個`form input`是我們的template去設計決定的,然後我們仍需要選擇一個template負責寄送response和data which we should use to populate this template. > >結論: 這些情況看似簡單,卻都是web開發的基礎。 ==Shannon Video Note== >課程目標: 聊解the flow of the web application three basic ways a user can interact with our app >1. **What We Use Templates For**: User Navigates to the App for the First time 1. Choose a template for the page 2. Add application data to the model * 當我們建立好tempate後,我們可以很有效率的留下一些洞給thymeleaf去填充那些data model, like which items are on sale aned at what discount. > >2. **User Navigates Within the App**: User click a link on our website, which takes them to a different view. 1. 我們可以讓user看Order Summary或是add an item to the cart 2. 當item added我們需要知道那些被added, which mean the request needs to carry identiformation about the user. (後續我們會學到怎麼安全包裝他們) > >3. **User Submits Data Through a From to the App**: They enter impormation into a form on our website and click submit. 1. 當submit購買清單後,user惠慶入payment and shipping information(之後我們會學~) # 4.MVC and You {%youtube OImSIFbkFB8%} MVC is an acrony(字母縮寫) that stands for Model-View-Controller, and it's a common software pattern for user interface design. Traditionally, it divides the roles of components in an app into three layers: * the Model, which is responsible for maintaining the state of an application, * the View, which is responsible for displaying the UI to the user, * and the Controller, which is responsible for processing user actions (sent from the View) to update the Model, and for forwarding those updates back to the View MVC is an abstract pattern, though, and every library implements it differently. Spring MVC is built around the browser as a platform, and it organizes these roles like this: * **HTML templates** are the views - each one represents a specific screen or screen component that the user is shown. * **Spring beans** are the controllers - specifically, Spring MVC gives an `@Controller` annotation that we can use to register our beans as controllers. Think of Spring bean controllers as specialized application components that can define methods to handle specific user requests. Those methods are responsible for choosing the HTML template that is generated in response, as well as for populating the `Model` object for that template. * `Model` objects are the models - every controller method can take an optional `Model` argument, and by reading and changing the data inside of it, the controller can read user-submitted data and populate the template with the changes. Think of the Model class a simple data-transfer object: something that can store various bits of data with keys to look that data up, and that can be passed between the browser, the template engine, and the controller to facilitate the transfer of data between the user and the application. ==Shannon Note== >MVC裡面的 View就是HTML templates(Thymeleaf) 然後Control是透過Spring Bean裡面的標籤@Controller去控制的,它可以用來處理特定用戶請求方法,然後填充Model object進去template裡面 Model : 每一個Controller可以選一個model參數,透這個model來改變裡面的資料,controller可以讀取user提交甚麼資料然後去填充改變template裡面的資料,一個簡單的資料傳輸物件which can store various bits of data witj keys to look that data up. 然後還可以在browser和template engine之間傳輸,template engine and the controller 可以加快資料的傳輸between the user and the application. Let's Get Coding! {%youtube IgWex0TOlyk%} `You can find the lecture sample code from the video above here :` https://github.com/udacity/nd035-c1-spring-boot-basics-examples/tree/master/udacity-jwdnd-c1-l3-mvc-and-you-1-master In order to start using Spring MVC, we need two main elements: an HTML template to define the user interface, and a Spring MVC `@Controller`-annotated bean to serve that template and populate it with data. In our example so far, our "template" is actually just a static HTML page that displays a greeting. The main takeaway about templates so far is to remember to place them in the right folder - `src/main/resources/templates` under the project root directory. When we choose a template in our controller, we do so by specifying the template name we want to load - our `home.html` template in the example is simply referred to as `"home"`. This will only work if your templates are in the right folder, so always double check! To set up a basic controller to serve this template, we created a new class called `HomeController` and annotated it with `@Controller`. As you may remember from the last lesson, this registers the class as a Spring bean and makes it eligible for request handling. That's why we can't just use `@Component` - **Spring MVC only looks at controllers, not all Spring beans.** In order to actually bind the controller to a specific request URL - like `/home` in our example - we have to define a method in the controller and annotate it with `@RequestMapping`. We also have to return a String from this method - this is the name of the template we want to render. For this first step into web development, that's all we do - return the String `"home"` to indicate that we want the `home.html` template to be rendered when a user requests the `/home` URL. ==Shannon Note== >把home.html放在`src/main/resources/templates`,然後透過`@Controller`來告訴她是處理request的class,Spring MVC only looks at controllers, not all Spring beans. > >Model這個class(需要`import org.springframework.ui.Model`)是一個class that Spring MVC 將會寄給Thymeleaf去Render the template。 > >我們可以透過`@RequestMapping`來設定這個controller的URL Basic User Flow {%youtube A_4BOd0pq3k%} lecture sample code from the video: https://github.com/udacity/nd035-c1-spring-boot-basics-examples/tree/master/udacity-jwdnd-c1-l3-mvc-and-you-2-master In order to actually render dynamic data in a template, we again need to approach it from both the template and the controller. In the template, we need to add Thymeleaf attributes to our HTML. In our example so far, we added the `th:text` attribute to the heading we want to be dynamic, like so: ```typescript <h1 th:text="${welcomeMessage}">Hello, homepage!</h1> ``` This attribute will cause Thymeleaf to replace the text inside the `h1` tag (`Hello, homepage!`) with a string generated by evaluating the expression in the `th:text` attribute (`${welcomeMessage}`). The syntax of this expression is fairly simple: the `${}` indicates an expression to evaluate, and by using a name like `welcomeMessage` inside of it, we're telling Thymeleaf to look up a value in the model supplied for this template with the same name. ==Shannon Note== >我們可以透過`S{welcomeMessage}`來告訴Thymeleaf去尋找一個值in the model, 這個model也有提供給這個template一樣的名稱 For that to work, though, we need to add a value named `welcomeMessage` to the model - and we do that in the controller method like so: ```typescript @RequestMapping("/home") public String getHomePage(Model model) { model.addAttribute("welcomeMessage", "Hi Hello"); return "home"; } ``` First we need to add an argument to the controller `method` - the Model object you see above. This is a special class that Spring MVC will send to Thymeleaf to render the template, and we can set various attributes on it to add named values. As you can see, we're adding a value of `"Hi Hello"` to the model with the name `"welcomeMessage"` - which is exactly the name we're referencing in our template! Now when we render the template, the message `Hi Hello` will appear on the web page instead of `Hello, homepage!` Nice! We can replace the hardcoded `"Hi Hello"` string in our controller with any Java value or expression, and it will be set every time the controller method is called, which means every time a request comes in for `/home`. That means we can set it dynamically, even based on the request that comes in. If we replace it with `Instant.now().toString()`, we end up with a welcome message that shows the current time, and updates every time we reload the page. ![](https://i.imgur.com/eJv1AxK.png) Key Terms * MVC: MVC is an acronym that stands for Model-View-Controller, and it's a common software pattern for user interface design * Model: in MVC, the Model is responsible for maintaining the state of an application * View: in MVC, the View is responsible for displaying the UI to the user, * Controller: in MVC, the Controller is responsible for processing user actions (sent from the View) to update the Model, and for forwarding those updates back to the View * Template: In software development, templates are used in many different contexts - in general, they are a way to define some often-repeated or reused text or code in a specific format, like HTML, along with code hooks that indicate portions of the template that should be replaced dynamically when the template is rendered. In our context, we mostly use Thymeleaf's HTML templates, which mostly look like plain HTML with a few extra Thymeleaf-specific attributes. These attributes are our code hooks, and allow us to define what data Thymeleaf uses when generating the final HTML from our template. Further Research * High-level Overview of Different MVC Variants * https://uniandes-se4ma.gitlab.io/books/chapter8/mvc-mvvm-mv-mvwhat.html * If you want a more in-depth analysis of the implementation differences of different MVC variants, check out this research paper. * https://uniandes-se4ma.gitlab.io/books/chapter8/mvc-mvvm-mv-mvwhat.html ==Shannon Note After Watching Vide== >1. 所有跟view相關的東西會放在resources/templates裡面,然後在java/com.example.mvc下新增controller package裡面添加你要用的Controller.class,標記`@Controller`這個方法就會被標記為bean且spring mvc會認定他為controller ```typescript @Controller public class HomeController { @RequestMapping("/home") public String getHomePage(){ //他會根據Return 的值去template找到home.html return "home"; } } ``` >如果你在Controller裡面標記RequestMapping("/home")當user輸入/home的URL時,他就會找到`getHomePage()`,然後根據回傳的值去對應到templates裡面有沒有相同名稱的html。 ```typescript @Controller public class HomeController { @RequestMapping("/home") public String getHomePage(Model model){ //我們可以透過這個知道our controller method 何時處理that request model.addAttribute("welcomeMessage", Instant.now().toString()); return "home"; } } ``` >你在這裡看到的th:text是Thymeleaf的屬性,我們透過增加`th:text`屬性告訴她我們想要dynamic,這個屬性將會讓Thymeleaf去替換the text the ```typescript=10 <body>= <h1 th:text="${welcomeMessage}">Hello, homepage!</h1> </body> ``` >以上兩段code順序是這樣的 >1. user 輸入URL /home >2. Spring MVC透過`@Controller`裡面的`@RequestMapping`找到相應的方法 >3. 以此為例,找到getHomePage方法,他會根據return的值,去找到templates裡面一樣名稱的.html,並且model會替換掉.html裡面有${...}的值 # 5.MVC and You Quizzes {%youtube mpTzYRpsmPE%} ==Shannon Note After Watching the Video== >* View = Browser >* Controller = Server >* Model = Database # 6.HTML Templates HTML Templates with Thymeleaf {%youtube WxhwoLDEzKE%} The nature of Spring MVC's data flow - the controller has to provide the data for the template it wants to render - means that often, when designing a new user-facing feature, it makes sense to start with the template. Thymeleaf is the HTML template engine we're using in this class, which means that it's a library that can take a template, a data model, and combine them to generate a final HTML document. The way that Thymeleaf applies the data model to the template is based on the Thymeleaf attributes we add to the template, like th:text from the previous lecture on MVC. These attributes can have complex expressions as their values, which are processed by Thymeleaf in the context of the data model provided. In the next video, we'll look at some of the effects those attributes and expressions can achieve! More Greetings! {%youtube zDks6PRZfY0%} **Sample Code: https://github.com/udacity/nd035-c1-spring-boot-basics-examples/tree/master/udacity-jwdnd-c1-l3-html-templates-master** In addition to setting text values, we can use Thymeleaf attributes to perform basic control flow in our templates. The main two types of control flow in templates are iteration and conditional rendering. **Iteration** in Thymeleaf templates works very similarly to an enhanced for-loop in Java. The main attribute used in template iteration is th:each, and its use looks like this: ```typescript <h1 th:each="msg : ${greetings}" th:text="${msg}">Hello, homepage!</h1> ``` We can read the attribute `th:each="msg : ${greetings}"` as "for each `msg` in `greetings`", and it essentially means "repeatedly render this element for each value in the `greetings` collection, and name that element msg for any expressions that need that name to have a value associated with it. So in this example, the `h1` tag will be repeatedly rendered, once for each element in `greetings`, and the text rendered by `th:text="${msg}"` will be the current element of `greetings` being rendered. If greetings contained the Strings "Hi" and "Hello", the final rendered html would be ```typescript <h1>Hi</h1> <h1>Hello</h1> ``` **Conditional rendering** in Thymeleaf usually looks like an if statement in Java, or occasionally a switch statement. The attribute we examined in the example was `th:unless`, as in: ```typescript <h1 th:unless="${msg.contains('goodbye')}" th:text="${msg}">Hello, homepage!</h1> ``` In this case, if the `msg` contains the String `"goodbye"`, the `h1` tag will not be rendered. This is particularly useful when choosing whether or not to render an error message, for example. If you need the opposite condition, in this case only showing messages that contain `"goodbye"`, you can simply replace the `th:unless` with `th:if`. **How Thymeleaf Renders a View** ![](https://i.imgur.com/acIKzyB.png) **Key Terms** * **User Action**: Broadly, a user action is simply some specific action a user can take, provided by the user interface they're interacting with. In the case of web applications, we usually think of user actions as clicks on a web page that often result in a HTTP request sent to the backend. * **Prototype/Wireframe** In the development process for a web application, it's common to first design the full HTML and CSS for all of the screens a user is expected to see. These pages have no actual functionality, and are usually called prototypes. Wireframes are an even earlier product of the design process, and usually are simple images that show what the prototypes should look like. **Further Reading** * The official Thymeleaf tutorial, which explains the entire framework from first principles. * https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#introducing-thymeleaf * The official Thymeleaf expression syntax tutorial. Read this if all those `${}`s aren't making much sense. * https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#introducing-thymeleaf * The official Spring Expression Language docs. This will tell you how to perform various computations inside of the Thymeleaf expression brackets. * https://docs.spring.io/spring/docs/4.3.10.RELEASE/spring-framework-reference/html/expressions.html ==Shannon Note== >* 凡是start with the template, so you can prototype * Prototype 可以早早決定需求 >* A Template Engine (Thymeleaf) > >contoller 需要提供Data給Tempate去render, Thymeleaf是HTML template engine, 他是一個library可以做出template, a data model, and combine them to generate a final HTML document. > >Thymeleaf是怎麼applies data model在template上面? 他是透過我們加在template的Thymeleaf attribute去達成的, like `th:text` > >* 基本Attribute > >1. 基本替換文字`odel.addAttribute("welcomeMessage", Instant.now().toString()); ` > template ```typescript <h1 th:text="${welcomeMessage}">Hello, homepage!</h1> ``` result ```typescript= <h1>2020-08-01T15:08:01.519184100Z</h1> ``` > >2. 陣列輸出多條訊息` model.addAttribute("greetings", new String[]{"Hi", "hello", "goodbye"}); ` template ```typescript <h1 th:each="msg : ${greetings}" th:text="${msg}">Hello, homepage~!</h1> ``` result ```typescript <h1>Hi</h1> <h1>hello</h1> <h1>goodbye</h1> ``` >3. 陣列中只輸出特定訊息` model.addAttribute("greetings", new String[]{"Hi", "hello", "goodbye"}); ` template ```typescript <h1 th:each="msg : ${greetings2}" th:text = "${msg}" th:if="${msg.contains('goodbye')}"> Hello, homepage? </h1> ``` result ```typescript <h1>goodbye</h1> ``` >4. 陣列中不要輸出特定訊息` model.addAttribute("greetings", new String[]{"Hi", "hello", "goodbye"}); ` template ```typescript <h1 th:each="msg : ${greetings2}" th:text = "${msg}" th:unless="${msg.contains('goodbye')}"> Hello, homepage? </h1> ``` result ```typescript <h1>Hi</h1> <h1>hello</h1> ``` >5. 補充 >可以寫成以下形式 ```typescript <tbody> <tr th:each="cat:${cats}"> <td th:text="${cat.color}"/> <td th:text="${cat.maxSpeedMph}"/> </tr> </tbody> //正確 <p th:text="${cat.name + 'is' + cat.color}"></p> //不可以寫成這樣 <p th:text="${cat.name} + 'is' + ${cat.color}"></p> <p th:if="${cat.maxSpeedMph > 10}">Pretty fast</p> ``` # 7.HTML Templates Quizzes {%youtube 1YD-dhb8sG0%} # 8.Exercise: HTML Templates Exercise: HTML Templates with Thymeleaf Let’s start with a simple example on our new webpage, simple-home.html. We have two different messages for our page, and we want to pick one or the other depending on whether we’re first landing on the page, or if we’ve submitted the form. Here’s the <body> text for our web page: ```typescript <body> <form action="#"> <input type="submit" value="Visit me"> </form> <h1>Hello, homepage!</h1> <h1>Welcome back!</h1> </body> ``` Let’s assume our web server can set a variable for us called `firstVisit` when the form is submitted. Your job for this exercise is to complete the following steps: Add a Thymeleaf attribute to the form that directs it to the `/simplehome` endpoint when the form action is taken. Make sure the form uses a POST request. Use Thymeleaf condition logic to display the first message if `firstVisit` is true, and display the second message if `firstVisit` is false. # 9.Solution: HTML Templates Solution: HTML Templates with Thymeleaf {%youtube 2tkoFO11mSQ%} This example should be pretty simple. Here’s the `<body>` text of our webpage: ```typescript <body> <form action="#" th:action="@{'/simplehome'}" method="POST"> <input type="submit" value="Visit me"> </form> <h1 th:if="${firstVisit}">Hello, homepage!</h1> <h1 th:unless="${firstVisit}">Welcome back!</h1> </body> ``` You can see we took the following steps: * Set th:action to our `/simplehome` endpoint * Set the method of our form to POST * Used `th:if` and `th:unless` to choose which message to display depending on the variable `firstVisit`. # 10.Connecting Controllers Connecting Controllers to Templates {%youtube FftIxiuGpKo%} The final piece of the Spring MVC puzzle we need to build fully capable web apps is the ability to handle user-submitted data. As before, there are two main components to this, one on the template side, the other on the controller side. On the template side, we need to define input fields for each piece of data we want to capture, and a `<form>` element to group them. When the form is submitted, the data will be encoded in the HTTP request that is sent, and can be extracted on the Spring side. On the Spring side of things, we need to define a POJO to hold the form data. We'll look at code details in the next video, but by defining this POJO we can pre-fill the form by setting its fields and adding it as a Model attribute when first rendering the template, and Spring can automatically extract the request data into that POJO when the form is submitted. Let's see how that works! User-Inputted Data {%youtube cyuvvthGgzM%} smaple code: https://github.com/udacity/nd035-c1-spring-boot-basics-examples/tree/master/udacity-jwdnd-c1-l3-connecting-controllers-1-master In this video, we looked at the HTML tags and Thymeleaf attribute we need to set up a form for the user to fill and submit to the server. Here's the template code saw: ```typescript <form th:object="${newMessage}" th:action="@{/home}" action="#" method="POST"> <input th:field="*{text}" type="text"> <input type="submit"> </form> ``` We use the `th:object` attribute to choose the POJO our form data should be added to, and the `th:actionattribute` to choose the URL to send the form submission HTTP request to. We use the special `@{}` syntax in the latter to tell Thymeleaf to make sure the URL is always relative to the actual server address - this doesn't make a huge difference in our current project, but it's good practice when referring to URLs on our server in a Thymleaf template. We also set `method="POST"` on the form to set the HTTP method of the resulting request. This is important! Remember that `GET` requests cannot contain any custom data - we need to use `POST` for our form data to actually get sent! In order to bind the individual form input data fields to the form-backing POJO's fields, we need to add the `th:field` attribute. We also need to use another special Thymeleaf expression syntax - `*{}`. This allows us to refer to fields on the form-backing POJO without using dot syntax - `th:field="*{text}"` in this example is equivalent to `th:field="${newMessage.text}"`. Persisting Data {%youtube VlEenjMSSQA%} sample code:https://github.com/udacity/nd035-c1-spring-boot-basics-examples/tree/master/udacity-jwdnd-c1-l3-connecting-controllers-2-master In this video, we looked at how to handle user-submitted data from the Spring controller side of things. Here are the finalized controller methods we saw: ```typescript @GetMapping("/home") public String getHomePage(@ModelAttribute("newMessage") MessageForm newMessage, Model model) { model.addAttribute("greetings", this.messageListService.getMessages()); return "home"; } @PostMapping("/home") public String addMessage(@ModelAttribute("newMessage") MessageForm messageForm, Model model) { messageListService.addMessage(messageForm.getText()); model.addAttribute("greetings", messageListService.getMessages()); messageForm.setText(""); return "home"; } ``` The key elements to focus on are the new arguments to each of these methods - the `MessageForm` class is a POJO specifically designed to hold the form data we defined in the previous video. For the `GET` request handling method, we declare the `MessageForm` argument to ensure that the object exists and is added to the model by Spring automatically. This is necessary, because Thymeleaf needs an object with the name `newMessage` to be present in the model to render properly, even if there isn't any data in the object yet. For the `POST` request handling method, we declare the `MessageForm` argument to tell Spring that it should look for data that matches that in the body of the request we're handling. Spring will then automatically extract that data and put it in a `MessageForm` object before calling our method, passing it to us so we can use the data as we see fit. In both cases, we're annotating this argument with `@ModelAttribute`. This allows us to specify that Spring should add the object to our `Model` before asking Thymeleaf to render the template. That means we don't have to add it manually! Pretty handy. Key Terms * **Form-Backing Object**: This is a term used by Spring MVC and Thymeleaf to mean an object that represents the data contained in a form. On the Spring side, this is usually an additional argument to the relevant Controller method, and on the Thymeleaf side, this is referred to in the th:object attribute on the form. Further Research * Official Spring MVC docs with some discussion of form-backing objects. * https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html * Official Thymeleaf docs for writing forms and integrating with Spring. * https://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#creating-a-form > ==Shannon Note After Watching the Video== > 我們可以設計`form action` 以及method來安排誰負責處理這個表單,每一個from 都必須有**backing object**。 > * backing object: 是一個簡單的POJO,可以在form裡面代表者data的type,用來裝form裡面的Data,通常會寫在`form th:object="${object name}"` > > 第二部影片重點 > 1. `th:object`: 用來選擇要用哪一個POJO去裝user送出去的資料 > 2. `th:action` : 用來選擇URL,去寄送form的HTTP request,我們會用`@{...}`來告訴Thymeleaf去確認URL的server address > 3. `method="POST"` : `from`無法使用`GET`來表寄送資料,`GET`不能包含任何custom data > 4. `th:field` + 搭配`*{attribute}` : 簡單來說就相當於`${object.attrite}`可以用來表達該物件的屬性 > > 第三部影片重點 > 1. `@GetMapping("/...")`: it only responds to getRequest, but其他功能跟`@RequestMapping`差不多 > 2. 如果使用`@PostConstruct`就表示當spring容器初始化的時候就會執行該方法,就不用特意去new一個新的object > 3. `@Service` : Service層位於Controler與Model中間,我要取得一個會員的資料,我是使用我的取得會員資料的服務去做處理,然後將處理完的結果存入Model中回傳,這樣可以讓我們的controller可以保持著程式碼識別度,在要修改Model層或controller層中的程式碼就不需要牽一髮動全身了 > >1. 如果user submit a form, controller可以透過@PostMapping("/home2")去取得資料(home是對上 form th:action="home2") >2. 如果重新載入頁面等普通的get要求,可以透過@GetMapping("/home)來尋找,(home是user輸入url所對上的結果) >3. 想要取得form th:object裡面的field="*{text}"內容 1. 先訂定好MessageForm,屬性必須有text才可以把*{text}內容存進去 ```typescript public class MessageForm { private String text; public String getText() { return text; } public void setText(String text) { this.text = text; } } ``` > 2. 在postmapping裡面,加入參數`@ModelAttribute("newMessage")` newMessage是來自form th:object="newMessage"的內容 > 3. 就可以透過getText()取得裡面的內容了 > > * POJO是甚麼?https://www.cnblogs.com/panchanggui/p/11610998.html * 一個很簡單的class不implement或extend任何class,有私有屬性,也有get, set方法。 # 11.Connecting Controllers Quizzes {%youtube hHftl3xElR0%} # 12.Connecting Controllers Exercise: Connecting Controllers to Templates This is another short HTML snippet like the one from our last exercise, but let’s make things a little trickier! This time, we have two fields and we’d like to map them to the variables on our message form called `animalName` and `adjective`. In the first `<h1>` element, you should list all the elements in our return list of `greetings`, just like we learned earlier, but this time we only want to do that if the size of our list is 5 or less. Once the list has more than 5 items in it, we want to display the second `<h1>` element. ```typescript <body> <form action="#"> <label for="animalText">Enter an Animal: </label> <input type="text" id="animalText" name="animalText"> <label for="adjective">Enter an Adjective:</label> <input type="text" id="adjective" name="adjective"> <input type="submit"> </form> <h1>Hello, homepage!</h1> <h1>I think that's enough!</h1> </body> ``` To complete this exercise. You need to use Thymeleaf to do four things: 1. Add an action to the form that directs it to the endpoint `/animal` using a POST request type and binds the form data to an object called `messageForm.` 2. Bind the input text to two fields called `animalName` and `adjective`. 3. Display the contents of the list `greetings` in the first `<h1>` element. You should display all the elements in the list. 4. Use conditional logic to only show the list of greetings if there are 5 or fewer messages. Otherwise, show the message ‘I think that’s enough!’ # 13. Solution: Connecting Controllers {%youtube SXZGcceGBeY%} Here’s the `<body>` text that completes this assignment: ```typescript <body> <form action="#" th:action="@{'/animal'}" th:object="${messageForm}" method="POST"> <label for="animalText">Enter an Animal: </label> <input type="text" id="animalText" name="animalText" th:field="*{animalName}"> <label for="adjective">Enter an Adjective:</label> <input type="text" id="adjective" name="adjective" th:field="*{adjective}"> <input type="submit"> </form> <h1 th:unless="${#lists.size(greetings) > 5}" th:each="msg : ${greetings}" th:text="${msg}">Hello, homepage!</h1> <h1 th:if="${#lists.size(greetings) > 5}">I think that's enough!</h1> </body> ``` You can see we made a few revisions to the `<form>` element: * We added `th:action` to set the target of the form submission. * We used `th:object` to bind the form to `messageForm`. * We added a `method=”POST”` attribute. We also added the `th:field` attribute to our input to reference the `animalName` and `adjective` values on our messageForm. To display the list of greetings, we use `th:each `and set the `th:text` for each row to the `msg` value. Lastly, we use `th:if` and `th:unless` to show or hide our two text elements. Note that they don’t have to be in any particular order. `th:if` and `th:unless` both can operate independently. # 14.Edge Case: Special Inputs 上傳檔案 You've been asked to write a Spring MVC controller that will manage file uploads. Which of these options looks like a method signature for a controller method that is meant to receive a file upload request? {%youtube HFnfUCP8eHA%} ==Shannon Note== >File Upload >一次能夠上傳的檔案數量有限,Http有定義一個multi-part request body fromat, 然後sring提供一個Datatype去代表這個file data called `MultiPartFile` > .html ```typescript <form action="#" enctype="multipart/form-data" th:action="@{/file-upload}" method="POST"> <input type="file" class="form-control-file" id="fileUpload" name="fileUpload"> <input type="submit"> </form> ``` >* enctype不是來自於thymeleaf,這個代表encoding type,我們正告訴browser to format resulting request as a multi-part file upload.這代表在Controller method裡面,我們可以增加MultiPartFile class作為一個參數 > .java ```typescript @PostMapping("/file-upload") public String handleFileUpload(@RequestParam("fileUpload") MultipartFile fileUpload, Model model){ InputStream fis = fileUpload.getInputStream(); //... } ``` >MultipartFile這個class是由spring來提供的,他允許我們去access the uploaded files contents without loading the entrie thing into memory. How? 透過InputStream. >`@RequestParam("fileUpload")` 這個標籤,我們需要這個標籤讓spring可以找到the right input in the form, `<input type="file" name="fileUpload">` > # 15.Final Review **Exercise: Final Review** For this final review, we'll be building on our project from last lesson to develop a rudimentary(初級的) chat application, where users can submit messages along with their username, and those messages (along with the usernames of the users who sent them) will be visible to any user that navigates to the /chat URL. Additionally, users should be able to select a message "mode": either `Say`, `Shout`, or `Whisper`. `Say` should display the message as written, while `Shout` should display the message in all-uppercase, and `Whisper` should display the message in all-lowercase. In order to accomplish this, you'll have to take following steps: **Disable Spring Security**. Unfortunately, since we added Spring Security dependencies to our project in the first lesson, by default all of our pages are restricted to logged-in users. We'll be learning about Spring security next lesson, so for now, let's comment out the dependency in our `pom.xml` file. Here are the dependencies that should be commented out: ```typescript <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> ``` **Add a `chat.html` template for the main application screen.** This template should have two parts: First, a form that allows users to submit their username, the message text they'd like to send to the chat, and the message "mode": `Say`, `Shout`, or`Whisper`. Second, some way to display the list of messages that have been sent so far. Here's some starter code for the form: ```typescript <form> <label for="username">Username:</label> <input id="username" type="text"> <label for="messageText">Message Text:</label> <input id="messageText" type="text"> <label for="messageType">Message Type: </label> <select id="messageType"> <option selected>Say</option> <option>Shout</option> <option>Whisper</option> </select> <input type="submit"> </form> ``` You're going to have to add Thymeleaf attributes to make this form work with the backend, and you might want to refer to the official Thymeleaf documentation on how to properly set up `<select>` tags in a form. For the message list, feel free to refer back to our examples this lesson for inspiration! Don't forget that you need to display both the message text and the username for each message. **Add a `ChatForm` class to hold the chat form data.** If we have a form, we need a form-backing object. Make sure its fields match the form input elements! **Add a `ChatMessage` class to hold the displayed message information**. Since we are displaying two pieces of data for each message, the message text and the sender's username, we should create a class to hold both at once. **Update the `MessageService` class to store a `List<ChatMessage>` as the chat history**. Since we want to keep track of many messages over time, we need a place to put them! **Update the `MessageService` class to have an `addMessage` method**. This method will be called by the controller to add a submitted message to the message list stored by the MessageService. **Add a `ChatController` class to serve the `chat.html` template and handle new message submissions**. We can't have a Spring MVC app without controllers! This controller should serve the chat.html template when a GET request comes in under the /chat URL, and it should handle POST requests at the same URL as new message submissions. **[BONUS] add a list of banned words**. Use that list to conditionally render messages on the page - messages that contain one or more banned words should not be displayed. **[EXTRA BONUS] Add some style**! Designing an attractive website is unfortunately out of scope for this class, but that doesn't mean you can't take matters into your own hands! If you feel comfortable writing your own styling code, add CSS and/or JavaScript files to make the app a little easier on the eyes. If you don't have a lot of experience with that kind of thing, but you'd like to learn, *Bootstrap* is a great place to start! # 16.Solution:Final Review {%youtube YYRUBJ9Ek80%} sample Code:https://github.com/udacity/nd035-c1-spring-boot-basics-examples/tree/master/udacity-jwdnd-c1-l3-final-review-solution-master Glossary * `GET` **Request**: an HTTP request for data at a specific URL. This type of request cannot include any additional data. * `POST` **Request**: and HTTP request that usually represents "posting" new data to the server. This is a common catch-all request method used for many data-bearing requests to the server. * **Dynamic**: Something that is dynamic changes in response to external stimuli. In the case of HTML templates, dynamic sections of the template are ones that can be replaced or configured with data on-demand. * **Static**: Something that is static does not change. In the case of HTML templates, static sections of the template are the ones that cannot be changed and will be the same no matter what data is used with the template. * **MVC**: Model-View-Controller, a design pattern that emphasizes the separation of application components into those three categories or layers for more-structured user-facing application development. * **Model**: in MVC, the Model is responsible for maintaining the state of an application, * **View**: in MVC, the View is responsible for displaying the UI to the user, * **Controller**: in MVC, the Controller is responsible for processing user actions (sent from the View) to update the Model, and for forwarding those updates back to the View * **Template**: In software development, templates are used in many different contexts - in general, they are a way to define some often-repeated or reused text or code in a specific format, like HTML, along with code hooks that indicate portions of the template that should be replaced dynamically when the template is rendered. In our context, we mostly use Thymeleaf's HTML templates, which mostly look like plain HTML with a few extra Thymeleaf-specific attributes. These attributes are our code hooks, and allow us to define what data Thymeleaf uses when generating the final HTML from our template. * **User Action**: Broadly, a user action is simply some specific action a user can take, provided by the user interface they're interacting with. In the case of web applications, we usually think of user actions as clicks on a web page that often result in a HTTP request sent to the backend. * **Prototype/Wireframe** In the development process for a web application, it's common to first design the full HTML and CSS for all of the screens a user is expected to see. These pages have no actual functionality, and are usually called prototypes. Wireframes are an even earlier product of the design process, and usually are simple images that show what the prototypes should look like. * **Form-Backing Object**: This is a term used by Spring MVC and Thymeleaf to mean an object that represents the data contained in a form. On the Spring side, this is usually an additional argument to the relevant Controller method, and on the Thymeleaf side, this is referred to in the `th:object` attribute on the form.

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully