# RESTful&AJAX 3/10 上課內容 (Maven) ###### tags: `RESTful&AJAX` # 80 REST 讀取所有會員資料 ![](https://i.imgur.com/azp5Zbx.png) # 81 REST 新增會員資料 ![](https://i.imgur.com/Tjyp2Nu.png) *** ## #### 改專案 ![](https://i.imgur.com/r6YRZtq.png) ![](https://i.imgur.com/iYrO9Ss.png) # 52 訊息轉換 ![](https://i.imgur.com/7nRsiab.png) #### 動態專案 早期沒有Maven ![](https://i.imgur.com/9ZFHF5R.png) #### Maven專案 ![](https://i.imgur.com/linjkqn.png) ![](https://i.imgur.com/MJNNhac.png) ![](https://i.imgur.com/cO9syYu.png) ![](https://i.imgur.com/BkvPWxI.png) * Versoin:1.0版本 * Packaging:現在是war檔 (spring boot 是jar檔) [Apache Tomcat](http://tomcat.apache.org/whichversion.html) #### pom.xml ```clike= <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>edu.ntu.eeit126</groupId> <artifactId>springRest</artifactId> <version>1.0</version> <packaging>war</packaging> <properties> <!--不需要用到xml打false 需要就改true --> <failOnMissingWebXml>true</failOnMissingWebXml> <!--改java11 --> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <!-- 改常數EL --> <hibernate.version>5.4.21.Final</hibernate.version> <spring.version>5.4.21.Final</spring.version> <spring.version>5.2.12.RELEASE</spring.version> </properties> <dependencies> <!--Dynamic web Module 4.0 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.3</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>com.microsoft.sqlserver</groupId> <artifactId>mssql-jdbc</artifactId> <version>8.2.2.jre11</version> </dependency> <!-- c3p0連線池的功能 --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency> <!-- 做成常數Final --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <!-- 自動加到類別路徑 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <!-- hibernate用 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <!-- JSON用 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-oxm</artifactId> <version>${spring.version}</version> </dependency> </dependencies> </project> <!-- ctrl+shift+f 可以調整 --> ``` ![](https://i.imgur.com/I28mYpX.png) * 建立xml 注意版本 ![](https://i.imgur.com/iiU7TsJ.png) ![](https://i.imgur.com/ygNMBmq.png) [Java Servlet API » 4.0.1](https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api/4.0.1) [JavaServer Pages(TM) API » 2.3.3](https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api/2.3.3) [JSTL » 1.2](https://mvnrepository.com/artifact/javax.servlet/jstl/1.2) * xml 2.5殺掉 改4.0 ![](https://i.imgur.com/Vfy21KS.png) ![](https://i.imgur.com/bTssgXj.png) [ Microsoft JDBC Driver For SQL Server » 8.2.2.jre11](https://mvnrepository.com/artifact/com.microsoft.sqlserver/mssql-jdbc/8.2.2.jre11) [C3P0 » 0.9.5.2](https://mvnrepository.com/artifact/com.mchange/c3p0/0.9.5.2) [Hibernate Core Relocation » 5.4.21.Final](https://mvnrepository.com/artifact/org.hibernate/hibernate-core/5.4.21.Final) [Spring Web MVC » 5.2.12.RELEASE](https://mvnrepository.com/artifact/org.springframework/spring-webmvc/5.2.12.RELEASE) [Jackson Databind » 2.9.4](https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind/2.9.4) #### web.xml 組態檔 ```clike= <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <display-name>springRest</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext.xml</param-value> </context-param> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/data-access.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app> ``` ![](https://i.imgur.com/ufGaoee.png) #### 類別路徑 必須要在resources之下 ![](https://i.imgur.com/UIDR3MN.jpg) ![](https://i.imgur.com/iUgyHQd.png) #### sessionFactory定義三樣資訊 * 1.連線 2.映射 3.進階 ![](https://i.imgur.com/ni3uuyU.png) * 方言 hibernate.cfg.xml *** * 額外:[SQLServer2012Dialect](https://docs.jboss.org/hibernate/orm/5.0/javadocs/org/hibernate/dialect/SQLServer2012Dialect.html) #### Employee ```clike= package proj.model; import java.sql.Date; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import com.fasterxml.jackson.annotation.JsonFormat; @Entity @Table(name="employee_rest") public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) Integer empPk; String employeeId; String name; Double salary; @JsonFormat(pattern = "yyyy-MM-dd") Date birthday; public Employee() { super(); } public Employee(Integer empPk, String employeeId, String name, Double salary, Date birthday) { super(); this.empPk = empPk; this.employeeId = employeeId; this.name = name; this.salary = salary; this.birthday = birthday; } public Integer getEmpPk() { return empPk; } public void setEmpPk(Integer empPk) { this.empPk = empPk; } public String getEmployeeId() { return employeeId; } public void setEmployeeId(String employeeId) { this.employeeId = employeeId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public String toString() { return "Employee [empPk=" + empPk + ", employeeId=" + employeeId + ", name=" + name + ", salary=" + salary + ", birthday=" + birthday + "]"; } } ``` #### BaseController ```clike= package proj.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @Controller public class BaseController { @GetMapping("/") public String index() { return "index"; } } ``` #### index.jsp ```clike= <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <div align='center'> <h2>專案首頁</h2> <hr> <a href="<c:url value='/insertEmployee' />" >1. 接收Server送回的JSON物件</a><br> <a href="<c:url value='/showAllEmployee' />" >2. 輸入會員資料</a><br> </div> </body> </html> ``` ![](https://i.imgur.com/M8OLxDd.png) #### EmployeeController ```clike= package proj.controller; import java.util.HashMap; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import proj.model.Employee; import proj.service.EmployeeService; @Controller public class EmployeeController { @Autowired EmployeeService employeeService; @PostMapping("/_02/CheckEmployeeId") public @ResponseBody Map<String, Object> checkEmployeeId(@RequestParam("id") String id) { Map<String, Object> map = new HashMap<String, Object>(); if (employeeService.checkEmployeeId(id)) { map.put("id", "已存在"); } else { map.put("id", ""); } return map; } @PostMapping("/employees") public @ResponseBody Map<String, Object> saveEmployee(@RequestBody Employee employee) { System.out.println("employee==>"+employee); Map<String, Object> map = new HashMap<String, Object>(); try { employeeService.save(employee); map.put("success", "新增成功"); } catch (Exception e) { map.put("fail", "新增失敗"); } return map; } } ``` #### EmployeeService ```clike= package proj.service; import proj.model.Employee; public interface EmployeeService { boolean checkEmployeeId(String id); void save(Employee employee); } ``` #### EmployeeServiceImpl ```clike= package proj.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import proj.model.Employee; import proj.repository.EmployeeRepository; import proj.service.EmployeeService; @Service public class EmployeeServiceImpl implements EmployeeService { @Autowired EmployeeRepository employeeRepository; @Transactional @Override public boolean checkEmployeeId(String id) { return employeeRepository.checkEmployeeId(id); } @Transactional @Override public void save(Employee employee) { employeeRepository.save(employee); } } ``` #### EmployeeRepository ```clike= package proj.repository; import proj.model.Employee; public interface EmployeeRepository { boolean checkEmployeeId(String id); void save(Employee employee); } ``` #### EmployeeRepositoryImpl ```clike= package proj.repository; import java.util.List; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import proj.model.Employee; @Repository public class EmployeeRepositoryImpl implements EmployeeRepository { @Autowired SessionFactory factory; @SuppressWarnings("unchecked") @Override public boolean checkEmployeeId(String id) { boolean exist = false; String hql = "FROM Employee e WHERE e.employeeId = :eid"; Session session = factory.getCurrentSession(); List<Employee> employees = session.createQuery(hql) .setParameter("eid", id) .getResultList(); if (employees.isEmpty()) { exist = false; } else { exist = true; } return exist; } @Override public void save(Employee employee) { if (checkEmployeeId(employee.getEmployeeId())) { //丟出例外 throw new RuntimeException("員工編號已存在,無法新增"); } Session session = factory.getCurrentSession(); session.save(employee); } } ``` * 404 請求找不到 * 405 get post #### register.jsp ```clike= <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <!DOCTYPE html> <html> <head> <link rel='stylesheet' href="<c:url value='/css/styles.css' />" > <script> var hasError = false; window.onload = function() { var alink = document.getElementById("accountCheck"); var div = document.getElementById('result0c'); alink.onclick = function() { var idValue = document.getElementById("id").value; if (!idValue) { div.innerHTML = "<font color='blue' size='-1'>請輸入員工編號...</font>"; return; } var xhr = new XMLHttpRequest(); xhr.open("POST", "<c:url value='/_02/CheckEmployeeId' />", true); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.send("id=" + idValue); var message = ""; xhr.onreadystatechange = function() { // 伺服器請求完成 if (xhr.readyState == 4 && xhr.status == 200) { var result = JSON.parse(xhr.responseText); if (result.id.length == 0) { message = "<font color='green' size='-2'>帳號可用</font>"; } else if ( result.id.startsWith("Error") ) { message = "<font color='red' size='-2'>發生錯誤: 員工編號" + result.id + "</font>"; } else { message = "<font color='red' size='-2'>帳號重複,請重新輸入員工編號</font>"; } div.innerHTML = message; } } } var sendData = document.getElementById("sendData"); sendData.onclick = function() { hasError = false; // 讀取欄位資料 var idValue = document.getElementById("id").value; var nameValue = document.getElementById("name").value; var salaryValue = document.getElementById("salary").value; var birthdayValue = document.getElementById("birthday").value; var div0 = document.getElementById('result0c'); var div1 = document.getElementById('result1c'); var div2 = document.getElementById('result2c'); var div3 = document.getElementById('result3c'); var divResult = document.getElementById('resultMsg'); if (!idValue){ setErrorFor(div0, "請輸入員工編號"); } else { div0.innerHTML = ""; } if (!nameValue){ setErrorFor(div1, "請輸入姓名"); } else { div1.innerHTML = ""; } if (!salaryValue){ setErrorFor(div2, "請輸入薪水"); } else { var objRegex = /^\d+$|(^-?\d\d*\.\d\d*$)|(^-?\.\d\d*$)/; if(!objRegex.test(salaryValue)) { setErrorFor(div2, "薪水欄必須是數值"); } else { div2.innerHTML = ""; } } if (!birthdayValue){ setErrorFor(div3, "請輸入生日"); } else if(!dateValidation(birthdayValue)) { setErrorFor(div3, "生日格式錯誤,正確格式為yyyy-MM-dd"); } else { div3.innerHTML = ""; } if (hasError){ return false; } var xhr1 = new XMLHttpRequest(); xhr1.open("POST", "<c:url value='/employees' />", true); var jsonMember = { "employeeId": idValue, "name": nameValue, "salary": salaryValue, "birthday": birthdayValue } xhr1.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); xhr1.send(JSON.stringify(jsonMember)); xhr1.onreadystatechange = function() { // 伺服器請求完成 if (xhr1.readyState == 4 && (xhr1.status == 200 || xhr1.status == 201) ) { result = JSON.parse(xhr1.responseText); if (result.fail) { divResult.innerHTML = "<font color='red' >" + result.fail + "</font>"; } else if (result.success) { divResult.innerHTML = "<font color='GREEN'>" + result.success + "</font>"; div0.innerHTML = ""; div1.innerHTML = ""; div2.innerHTML = ""; div3.innerHTML = ""; } else { if (result.idError) { div0.innerHTML = "<font color='green' size='-2'>" + result.idError + "</font>"; } else { div0.innerHTML = ""; } if (result.nameError) { div1.innerHTML = "<font color='green' size='-2'>" + result.nameError + "</font>"; } else { div1.innerHTML = ""; } if (result.salaryError) { div2.innerHTML = "<font color='green' size='-2'>" + result.salaryError + "</font>"; } else { div2.innerHTML = ""; } if (result.birthdayError) { div3.innerHTML = "<font color='green' size='-2'>" + result.birthdayError + "</font>"; } else { div3.innerHTML = ""; } } } } } } function setErrorFor(input, message){ input.innerHTML = "<font color='red' size='-2'>" + message + "</font>"; hasError = true; } function dateValidation(str) { var re = new RegExp("^([0-9]{4})[.-]{1}([0-9]{1,2})[.-]{1}([0-9]{1,2})$"); var days = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; var strDataValue; var valid = true; if ((strDataValue = re.exec(str)) != null) { var y, m, d; y = parseFloat(strDataValue[1]); if (y <= 0 || y > 9999) { /*年*/ return false; } m = parseFloat(strDataValue[2]); if (m < 1 || m > 12) { /*月*/ return false; } d = parseFloat(strDataValue[3]); if ( y % 4 == 0 && y % 100 != 0 || y % 400 == 0 ){ days[2] = 29; } else { days[2] = 28; } if (d <= 0 || d > days[m]) { /*日*/ valid = false; } } else { valid = false; } return valid; } function isEmail(email) { return /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(email); } </script> <link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/css/styles.css"> <meta charset="UTF-8"> <title>Registration</title> </head> <body> <div align='center'> <h3>輸入員工資料</h3> <hr> <div id='resultMsg' style="height: 18px; font-weight: bold;"></div> <br> <fieldset style='display: inline-block; width: 820px;'> <legend>填寫下列資料</legend> <table border='1'> <tr height='60'> <td width='200'>&nbsp;</td> <td width='400'> &nbsp;編號: <input type="text" name="id" id='id'><br> <div style='font-size: 10pt; text-align: center;'> <a href='#' id='accountCheck' style='font-size: 10pt;'>檢查編號</a> </div> </td> <td width='200'> <div id='result0c' style="height: 10px;"></div><br> <div id='result0s' style="height: 10px;"></div> </td> </tr> <tr height='60'> <td width='200'>&nbsp;</td> <td width='400'> &nbsp;姓名: <input type="text" name="name" id='name'><br> </td> <td width='200' style="vertical-align:top"> <div id='result1c' style="height: 10px;"></div><br> <div id='result1s' style="height: 10px;"></div> </td> </tr> <tr height='60'> <td width='200'>&nbsp;</td> <td width='400'> &nbsp;薪水: <input type="text" name="salary" id='salary'><br> </td> <td width='200' style="vertical-align:top"> <div id='result2c' style="height: 10px;"></div><br> <div id='result2s' style="height: 10px;"></div> </td> </tr> <tr height='60'> <td width='200'>&nbsp;</td> <td width='400'> &nbsp;生日: <input type="text" name="birthday" id='birthday' size='24'> </td> <td width='200'> <div id='result3c' style="height: 10px;"></div><br> <div id='result3s' style="height: 10px;"></div> </td> </tr> <tr height='50'> <td colspan='3' align='center'><button id='sendData'>送出</button></td> </tr> </table> </fieldset> <hr> <p> <a href="<c:url value='/' />">回前頁</a> <hr> </div> </body> </html> ``` ### 我先統一丟這邊 ```clike= @Override public List<Employee> getAllEmployees() { String hql = "FROM Employee"; Session session = factory.getCurrentSession(); @SuppressWarnings("unchecked") List<Employee> employees = session.createQuery(hql).getResultList(); return employees; } ``` ```clike= List<Employee> getAllEmployees(); ``` ```clike= @Transactional @Override public List<Employee> getAllEmployees() { return employeeRepository.getAllEmployees(); } ``` ```clike= List<Employee> getAllEmployees(); ``` ```clike= @GetMapping("/showAllEmployee") public @ResponseBody List<Employee> getAllEmployees() { return employeeService.getAllEmployees(); } ``` # Entity類別:Member ![](https://i.imgur.com/QMZZpvo.png) # postman https://www.postman.com/downloads/ * win64 ![](https://i.imgur.com/TskR4Py.png) ![](https://i.imgur.com/tA06LAP.png) ## 生資料 ![](https://i.imgur.com/KZciDsi.png) ![](https://i.imgur.com/4mlDqKE.png) ## 報錯 ![](https://i.imgur.com/iqZtCl6.png) ## 成功 ![](https://i.imgur.com/PXTG2Sx.png) ## 更新 ![](https://i.imgur.com/kRWanMk.png) ## 刪除 ![](https://i.imgur.com/WgXCbIg.png) # 專案規則 ![](https://i.imgur.com/QXe5Bpl.png)