<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # Tomcat Derby 教程 原文:http://zetcode.com/java/tomcatderby/ 在本教程中,我們將使用 Tomcat 和 Derby。 該應用分為四個層,它具有一個控制器,并使用 DAO 訪問數據。 對于項目創建,我們使用 NetBeans IDE。 源代碼可從作者的 Github [TomcatDerby](https://github.com/janbodnar/TomcatDerby) 倉庫中獲得。 現代 Java Web 應用主要通過使用諸如 Spring 或 Vaadin 之類的框架來創建。 但是有必要了解基礎。 我們使用`pure.css`庫來幫助創建用戶界面。 Apache Derby 是完全用 Java 實現的開源關系數據庫。 它占地面積小,易于部署和安裝。 它支持嵌入式和客戶端/服務器模式。 Apache Tomcat 是 Java Servlet,JavaServer Pages,Java Expression Language 和 Java WebSocket 技術的開源實現。 數據訪問對象(DAO) 是為數據庫或其他持久性機制提供抽象接口的對象。 DAO 完全向其客戶端隱藏了數據源實現細節。 它充當組件和數據源之間的適配器。 ## Java Web 應用 我們在 NetBeans 中創建一個新的 Web 應用。 該應用管理一個簡單的`Cars`表。 它將創建新的汽車,檢索一輛汽車和所有汽車。 該應用分為四個層:表示層,模型層,服務層和持久層。 Web 應用的多層設置是重要的軟件開發模式。 ```java $ tree . ├── nb-configuration.xml ├── pom.xml ├── README.md └── src ├── main │ ├── java │ │ └── com │ │ └── zetcode │ │ ├── bean │ │ │ └── Car.java │ │ ├── persistence │ │ │ ├── CarDAO.java │ │ │ ├── Executable.java │ │ │ └── JdbcDAO.java │ │ ├── service │ │ │ ├── CarsService.java │ │ │ └── ICarsService.java │ │ ├── util │ │ │ ├── DBUtils.java │ │ │ ├── ServiceLocator.java │ │ │ └── ValidateParameter.java │ │ └── web │ │ └── Controller.java │ └── webapp │ ├── allCars.jsp │ ├── carSaved.jsp │ ├── index.jsp │ ├── META-INF │ │ └── context.xml │ ├── readCarId.jsp │ ├── readCar.jsp │ ├── showCar.jsp │ ├── unknown.jsp │ ├── WEB-INF │ └── wrongParams.jsp └── test └── java ``` 這是項目結構。 `pom.xml` ```java <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mycompany</groupId> <artifactId>DerbyTomcat</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>DerbyTomcat</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.derby</groupId> <artifactId>derbyclient</artifactId> <version>10.14.1.0</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.7</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.2.0</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </build> </project> ``` `pom.xml`包含項目依賴項:servlet 的 JAR,JSP 頁面,Derby 數據庫驅動程序,JSTL 庫以及某些幫助程序類的 Apache Commons Lang JAR。 ![Database creation](https://img.kancloud.cn/f6/a8/f6a8047083d0aeebfed1a31f5982223d_349x182.jpg) 圖:數據庫創建 在“服務”選項卡中,我們右鍵單擊 Java DB 節點,然后選擇“創建數據庫”選項。 我們給它命名為`testdb`。 該數據庫位于用戶主目錄的`.netbeans_derby`目錄中。 `cars.sql` ```java CREATE TABLE CARS(ID BIGINT NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1), NAME VARCHAR(30), PRICE INT); INSERT INTO CARS(Name, Price) VALUES('Audi', 52642); INSERT INTO CARS(Name, Price) VALUES('Mercedes', 57127); INSERT INTO CARS(Name, Price) VALUES('Skoda', 9000); INSERT INTO CARS(Name, Price) VALUES('Volvo', 29000); INSERT INTO CARS(Name, Price) VALUES('Bentley', 350000); INSERT INTO CARS(Name, Price) VALUES('Citroen', 21000); INSERT INTO CARS(Name, Price) VALUES('Hummer', 41400); INSERT INTO CARS(Name, Price) VALUES('Volkswagen', 21600); ``` 這是創建`Cars`表的 SQL。 汽車對象的 ID 會自動增加。 我們可以使用 NetBeans 工具創建`Cars`表。 我們右鍵單擊“數據庫”節點,然后選擇“新建連接”選項。 ![Connection wizard](https://img.kancloud.cn/a4/c4/a4c4ccf73a9399ec916b6ed66eec2f43_602x452.jpg) 圖:連接向導 我們在連接向導中填寫必要的詳細信息。 我們使用 Derby 網絡驅動程序; Derby 的端口是 1527。 ![Connections](https://img.kancloud.cn/11/94/1194c71b1a3f51193b20849bf5c549f9_349x108.jpg) 圖:連接 創建一個新的連接對象; 它由橙色圖標表示。 其上下文菜單提供了用于連接到指定數據庫并執行命令的選項。 “執行命令”選項顯示了執行 SQL 命令的工具。 在此窗口中,我們可以使用上面的 SQL 創建`Cars`表。 ![NetBeans Derby tool](https://img.kancloud.cn/62/d7/62d7993ac2c65b84b1a39c58e7eb4835_688x242.jpg) 圖:NetBeans Derby 工具 NetBeans 具有有用的 Derby 工具,可用于管理 Derby 數據庫。 `context.xml` ```java <?xml version="1.0" encoding="UTF-8"?> <Context path="/DerbyTomcat"> <Resource name="jdbc/testdb" auth="Container" type="javax.sql.DataSource" driverClassName="org.apache.derby.jdbc.ClientDriver" username="app" password="app" url="jdbc:derby://localhost:1527/testdb" maxActive="10" maxIdle="4" /> </Context> ``` 在`META-INF`目錄中的`context.xml`文件中,我們提供了數據源。 使用 JNDI API 查找資源。 ### 模型層 模型層具有`Car`類。 `Car.java` ```java package com.zetcode.bean; import java.util.Objects; public class Car { private Long id; private String name; private int price; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } @Override public int hashCode() { int hash = 7; hash = 61 * hash + Objects.hashCode(this.id); hash = 61 * hash + Objects.hashCode(this.name); hash = 61 * hash + this.price; return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Car other = (Car) obj; if (this.price != other.price) { return false; } if (!Objects.equals(this.name, other.name)) { return false; } return Objects.equals(this.id, other.id); } } ``` `Car`類具有三個屬性以及相應的獲取器和設置器方法。 ### 表示層 應用的表示層包含 JSP 頁面,這些頁面構建了應用的用戶界面。 `index.jsp` ```java <%@page contentType="text/html" pageEncoding="UTF-8"%> <%@page trimDirectiveWhitespaces="true"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html> <head> <title>Home page</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h2>Home page</h2> <p>Available actions:</p> <ul> <li><a href="controller?action=listcars">Show all</a></li> <li><a href="controller?action=readbyid">Show car by ID</a></li> <li><a href="controller?action=readcar">Create a new car</a></li> </ul> <a href="<%= request.getContextPath() %>">Home</a> </body> </html> ``` `index.jsp`頁面包含三個可用操作的鏈接:顯示所有汽車,顯示通過其 ID 找到的汽車以及創建新汽車。 ```java <a href="<%= request.getContextPath() %>">Home</a> ``` 使用`getContextPath()`方法,我們可以獲得主頁路徑。 `allCars.jsp` ```java <%@page contentType="text/html" pageEncoding="UTF-8"%> <%@page trimDirectiveWhitespaces="true"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html> <head> <title>Cars</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://unpkg.com/purecss@1.0.0/build/pure-min.css" integrity="sha384-nn4HPE8lTHyVtfCBi5yW9d20FjT8BJwUXyWZT9InLYax14RDjBj46LmSztkmNP9w" crossorigin="anonymous"> <style> body { padding:1em } nav { margin-top: 2em } </style> </head> <body> <h2>All cars</h2> <table class="pure-table pure-table-horizontal"> <thead> <tr> <th>Id</th> <th>Name</th> <th>Price</th> </tr> </thead> <c:forEach items="${carList}" var='car'> <tr> <td> <c:out value="${car.id}"/> </td> <td> <c:out value="${car.name}"/> </td> <td> <c:out value="${car.price}"/> </td> </tr> </c:forEach> </table> <a href="<%= request.getContextPath() %>">Home</a> </body> </html> ``` 在`allCars.jsp`頁面中,JSTL 的`<c:forEach>`和`<c:out>`標簽用于打印每個返回的汽車對象的屬性。 ```java <table class="pure-table pure-table-horizontal"> ``` 我們使用`pure.css`類來設計表。 `readCar.jsp` ```java <%@page contentType="text/html" pageEncoding="UTF-8"%> <%@page trimDirectiveWhitespaces="true" %> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html> <head> <title>Car details</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://unpkg.com/purecss@1.0.0/build/pure-min.css" integrity="sha384-nn4HPE8lTHyVtfCBi5yW9d20FjT8BJwUXyWZT9InLYax14RDjBj46LmSztkmNP9w" crossorigin="anonymous"> <style> body { padding:1em } nav { margin-top: 2em } </style> </head> <body> <form class="pure-form pure-form-stacked" action="controller?action=savecar" method="post"> <legend>Enter car details:</legend> <label for="carName">Name:</label> <input id="carName" type="text" name="carName"> <label for="carPrice">Price:</label> <input id ="carPrice" type="text" name="carPrice"> <button class="pure-button pure-button-primary" type="submit">Submit</button> </form> <a href="<%= request.getContextPath() %>">Home</a> </body> </html> ``` 在`readCar.jsp`頁面上,我們有一個表格來輸入新車的詳細信息。 `readCarId.jsp` ```java <%@page contentType="text/html" pageEncoding="UTF-8"%> <%@page trimDirectiveWhitespaces="true"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html> <head> <title>Enter car ID</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://unpkg.com/purecss@1.0.0/build/pure-min.css" integrity="sha384-nn4HPE8lTHyVtfCBi5yW9d20FjT8BJwUXyWZT9InLYax14RDjBj46LmSztkmNP9w" crossorigin="anonymous"> <style> body { padding:1em } nav { margin-top:2em } </style> </head> <body> <form class="pure-form pure-form-stacked" action="controller"> <legend>Enter car Id</legend> <input type="hidden" name="action" value="viewcar"> <label for="carId">Id:</label> <input id="carId" type="text" name="carId"> <button class="pure-button pure-button-primary" type="submit">Submit</button> </form> <a href="<%= request.getContextPath() %>">Home</a> </body> </html> ``` 在`readCarId.jsp`文件中,我們有一個表格來輸入我們要檢索的汽車 ID。 `carSaved.jsp` ```java <%@page contentType="text/html" pageEncoding="UTF-8"%> <%@page trimDirectiveWhitespaces="true"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE html> <html> <head> <title>Car saved</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <p> Successfully saved <c:out value="${sessionScope.carName}"/> car priced <c:out value="${sessionScope.carPrice}"/> </p> <a href="<%= request.getContextPath() %>">Home</a> </body> </html> ``` 在`carSaved.jsp`頁面中,我們僅通知您已保存具有給定名稱和價格的汽車。 我們使用 JSTL 庫中的`<c:out>`標簽。 `showCar.jsp` ```java <%@page contentType="text/html" pageEncoding="UTF-8"%> <%@page trimDirectiveWhitespaces="true"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html> <head> <title>Returned car</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h2>Car details</h2> <ul> <li>ID: <c:out value="${returnedCar.id}"/></li> <li>Name: <c:out value="${returnedCar.name}"/></li> <li>Price: <c:out value="${returnedCar.price}"/></li> </ul> <a href="<%= request.getContextPath() %>">Home</a> </body> </html> ``` 在`showCar.jsp`頁面中,我們顯示檢索到的汽車的屬性。 `unknown.jsp` ```java <%@page contentType="text/html" pageEncoding="UTF-8"%> <%@page trimDirectiveWhitespaces="true"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE html> <html> <head> <title>Unknown action</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h2>Unknown action</h2> <a href="<%= request.getContextPath() %>">Home</a> </body> </html> ``` 當控制器收到未定義的動作時,將顯示`unknown.jsp`頁面。 `wrongParams.jsp` ```java <%@page contentType="text/html" pageEncoding="UTF-8"%> <%@page trimDirectiveWhitespaces="true"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE html> <html> <head> <title>Wrong parameters</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h2>Wrong parameters specified</h2> <a href="<%= request.getContextPath() %>">Home</a> </body> </html> ``` 請求參數無效時,顯示`wrongParams.jsp`頁面。 創建名為`ValidateParameter`的工具類以確保請求參數的有效性。 ### 服務層 服務層提供邏輯以對發送到 DAO 和從 DAO 發送的數據進行操作。 `ICarsService.java` ```java package com.zetcode.service; import com.zetcode.bean.Car; import java.util.List; public interface ICarsService { public List<Car> findAllCars(); public Car findCar(Long id); public void saveCar(Car car); } ``` `ICarsService`為汽車服務提供了三種合同方式。 我們提供了一種檢索所有汽車,查找特定汽車并保存新汽車的方法。 `CarsService.java` ```java package com.zetcode.service; import com.zetcode.bean.Car; import com.zetcode.persistence.CarDAO; import com.zetcode.persistence.JdbcDAO; import java.util.List; public class CarsService implements ICarsService { @Override public List<Car> findAllCars() { CarDAO carDAO = new JdbcDAO(); return carDAO.findAll(); } @Override public Car findCar(Long id) { CarDAO carDAO = new JdbcDAO(); return carDAO.findCar(id); } @Override public void saveCar(Car car) { CarDAO carDAO = new JdbcDAO(); carDAO.saveCar(car); } } ``` `CarsService`提供合同方法的實現。 ```java @Override public List<Car> findAllCars() { CarDAO carDAO = new JdbcDAO(); return carDAO.findAll(); } ``` `findAllCars()`方法創建一個`JdbcDAO`并調用其`findAll()`方法。 ### 持久層 在持久層中,我們應用 DAO 模式。 DAO 在定義的 API 中隱藏了數據庫編程的復雜性。 `CarDAO.java` ```java package com.zetcode.persistence; import com.zetcode.bean.Car; import java.util.List; public interface CarDAO { public void saveCar(Car car); public Car findCar(Long id); public List<Car> findAll(); } ``` 這是`CarDAO`接口,顯示用于訪問我們的數據庫的方法簽名。 `Executable.java` ```java package com.zetcode.persistence; import java.sql.SQLException; import javax.naming.NamingException; public interface Executable { void exec() throws SQLException, NamingException; } ``` `Executable`接口是將`try/catch/finally`樣板放入`exec()`方法的合約。 `JdbcDAO.java` ```java package com.zetcode.persistence; import com.zetcode.bean.Car; import com.zetcode.util.DBUtils; import com.zetcode.util.ServiceLocator; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.naming.NamingException; import java.sql.SQLException; import javax.sql.DataSource; public class JdbcDAO implements CarDAO { private static final String DATA_SOURCE = "java:comp/env/jdbc/testdb"; private Connection con; private ResultSet rs; private PreparedStatement pst; @Override public void saveCar(Car car) { execute(() -> { DataSource ds = ServiceLocator.getDataSource(DATA_SOURCE); con = ds.getConnection(); pst = con.prepareStatement("INSERT INTO CARS(Name, Price) VALUES(?, ?)"); pst.setString(1, car.getName()); pst.setInt(2, car.getPrice()); pst.executeUpdate(); }); } @Override public Car findCar(Long id) { Car car = new Car(); execute(() -> { DataSource ds = ServiceLocator.getDataSource(DATA_SOURCE); con = ds.getConnection(); pst = con.prepareStatement("SELECT * FROM CARS WHERE Id = (?)"); pst.setLong(1, id); rs = pst.executeQuery(); if (rs.next()) { car.setId(rs.getLong(1)); car.setName(rs.getString(2)); car.setPrice(rs.getInt(3)); } }); return car; } @Override public List<Car> findAll() { List<Car> carList = new ArrayList<>(); execute(() -> { DataSource ds = ServiceLocator.getDataSource(DATA_SOURCE); con = ds.getConnection(); pst = con.prepareStatement("SELECT * FROM CARS"); rs = pst.executeQuery(); while (rs.next()) { Car car = new Car(); car.setId(rs.getLong(1)); car.setName(rs.getString(2)); car.setPrice(rs.getInt(3)); carList.add(car); } }); return carList; } private void execute(Executable executable) { try { executable.exec(); } catch (NamingException | SQLException e) { Logger lgr = Logger.getLogger(JdbcDAO.class.getName()); lgr.log(Level.SEVERE, e.getMessage(), e); } finally { DBUtils.closeResultSet(rs); DBUtils.closeStatement(pst); DBUtils.closeConnection(con); } } } ``` `JdbcDAO`是`CarDAO`接口的具體實現。 它使用 JDBC 從`Cars`表中插入和檢索數據。 ```java private static final String DATA_SOURCE = "java:comp/env/jdbc/testdb"; ``` 這是用于定位`testdb`數據庫的 JNDI 資源名稱。 ```java @Override public void saveCar(Car car) { execute(() -> { DataSource ds = ServiceLocator.getDataSource(DATA_SOURCE); con = ds.getConnection(); pst = con.prepareStatement("INSERT INTO CARS(Name, Price) VALUES(?, ?)"); pst.setString(1, car.getName()); pst.setInt(2, car.getPrice()); pst.executeUpdate(); }); } ``` `saveCar()`方法保存一個新的汽車對象。 `ServiceLocator.getDataSource()`方法查找并返回數據源。 該代碼已插入`execute()`方法中,該方法將處理`try/catch/finally`樣板。 ```java @Override public Car findCar(Long id) { Car car = new Car(); execute(() -> { DataSource ds = ServiceLocator.getDataSource(DATA_SOURCE); con = ds.getConnection(); pst = con.prepareStatement("SELECT * FROM CARS WHERE Id = (?)"); pst.setLong(1, id); rs = pst.executeQuery(); if (rs.next()) { car.setId(rs.getLong(1)); car.setName(rs.getString(2)); car.setPrice(rs.getInt(3)); } }); return car; } ``` `findCar()`方法從`Cars`表中檢索新車。 它執行準備好的語句,該語句接收汽車的 ID。 一個新的`car` bean 填充了返回的數據。 ```java private void execute(Executable executable) { try { executable.exec(); } catch (NamingException | SQLException e) { Logger lgr = Logger.getLogger(JdbcDAO.class.getName()); lgr.log(Level.SEVERE, e.getMessage(), e); } finally { DBUtils.closeResultSet(rs); DBUtils.closeStatement(pst); DBUtils.closeConnection(con); } } ``` 處理異常的重復代碼位于`execute()`方法中。 ### 工具類 我們創建了三個工具類:`ServiceLocator`,`ValidateParameter`和`DBUtils`。 這些類位于`com.zetcode.util`包中。 `ServiceLocator.java` ```java package com.zetcode.util; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; public class ServiceLocator { public static DataSource getDataSource(String jndiName) throws NamingException { Context ctx = new InitialContext(); DataSource ds = (DataSource) ctx.lookup(jndiName); return ds; } } ``` `ServiceLocator`查找并返回數據源。 從`JdbcDAO`類調用它。 數據源的詳細信息在`context.xml`文件中指定。 `ValidateParameter.java` ```java package com.zetcode.util; import org.apache.commons.lang3.math.NumberUtils; public class ValidateParameter { private static final int MAX_PRICE_CAR = 10_000_000; public static boolean validateName(String param) { return !(null == param || "".equals(param)); } public static boolean validateId(String param) { return !(null == param || "".equals(param) || !NumberUtils.isCreatable(param)); } public static boolean validatePrice(String param) { if (null == param || "".equals(param) || !NumberUtils.isCreatable(param)) { return false; } int price = Integer.valueOf(param); return !(price < 0 || price > MAX_PRICE_CAR); } } ``` `ValidateParameter`具有用于驗證請求參數的靜態方法。 例如,ID 必須為數字,且價格不得為負。 我們使用 Apache Commons Lang 庫中的`NumberUtils.isCreatable()`方法來確保參數為數字。 `DBUtils.java` ```java package com.zetcode.util; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.logging.Level; import java.util.logging.Logger; public class DBUtils { private static final Logger logger = Logger.getLogger(DBUtils.class.getName()); public static void closeResultSet(ResultSet rs) { if (rs != null) { try { rs.close(); } catch (SQLException ex) { logger.log(Level.FINEST, "Could not close JDBC ResultSet", ex); } catch (Throwable ex) { // We don't trust the JDBC driver: It might throw RuntimeException or Error. logger.log(Level.FINEST, "Unexpected exception on closing JDBC ResultSet", ex); } } } public static void closeStatement(Statement stmt) { if (stmt != null) { try { stmt.close(); } catch (SQLException ex) { logger.log(Level.FINEST, "Could not close JDBC Statement", ex); } catch (Throwable ex) { // We don't trust the JDBC driver: It might throw RuntimeException or Error. logger.log(Level.FINEST, "Unexpected exception on closing JDBC Statement", ex); } } } public static void closeConnection(Connection con) { if (con != null) { try { con.close(); } catch (SQLException ex) { logger.log(Level.FINEST, "Could not close JDBC Connection", ex); } catch (Throwable ex) { // We don't trust the JDBC driver: It might throw RuntimeException or Error. logger.log(Level.FINEST, "Unexpected exception on closing JDBC Connection", ex); } } } } ``` `DBUtils`包含釋放數據庫資源和處理異常的方法。 ### 控制器 `Controller`是一個 Servlet,它接收傳入的請求,調用服務方法并發送響應。 `Controller.java` ```java package com.zetcode.web; import com.zetcode.bean.Car; import com.zetcode.persistence.CarDAO; import com.zetcode.persistence.JdbcDAO; import com.zetcode.service.CarsService; import com.zetcode.service.ICarsService; import com.zetcode.util.ValidateParameter; import java.io.IOException; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(name = "Controller", urlPatterns = {"/controller"}) public class Controller extends HttpServlet { private static final String ACTION_KEY = "action"; private static final String READ_CAR_BY_ID_VIEW = "readCarId.jsp"; private static final String SHOW_CAR_VIEW = "showCar.jsp"; private static final String READ_CAR_VIEW = "readCar.jsp"; private static final String CAR_SAVED_VIEW = "carSaved.jsp"; private static final String ALL_CARS_VIEW = "allCars.jsp"; private static final String UNKNOWN_VIEW = "unknown.jsp"; private static final String WRONG_PARAMS_VIEW = "wrongParams.jsp"; private static final String LIST_CARS_ACTION = "listcars"; private static final String READ_CAR_BY_ID_ACTION = "readbyid"; private static final String READ_CAR_ACTION = "readcar"; private static final String VIEW_CAR_ACTION = "viewcar"; private static final String SAVE_CAR_ACTION = "savecar"; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); String actionName = request.getParameter(ACTION_KEY); String page = UNKNOWN_VIEW; if (LIST_CARS_ACTION.equals(actionName)) { ICarsService service = new CarsService(); request.setAttribute("carList", service.findAllCars()); page = ALL_CARS_VIEW; } if (READ_CAR_BY_ID_ACTION.equals(actionName)) { page = READ_CAR_BY_ID_VIEW; } if (READ_CAR_ACTION.equals(actionName)) { page = READ_CAR_VIEW; } if (VIEW_CAR_ACTION.equals(actionName)) { String sid = request.getParameter("carId"); if (ValidateParameter.validateId(sid)) { ICarsService service = new CarsService(); Long carId = Long.valueOf(sid); request.setAttribute("returnedCar", service.findCar(carId)); page = SHOW_CAR_VIEW; } else { page = WRONG_PARAMS_VIEW; } } RequestDispatcher disp = getServletContext().getRequestDispatcher("/" + page); disp.forward(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); String actionName = request.getParameter(ACTION_KEY); String page = UNKNOWN_VIEW; if (SAVE_CAR_ACTION.equals(actionName)) { String sname = request.getParameter("carName"); String sprice = request.getParameter("carPrice"); if (ValidateParameter.validateName(sname) && ValidateParameter.validatePrice(sprice)) { Car car = new Car(); car.setName(sname); car.setPrice(Integer.valueOf(sprice)); ICarsService service = new CarsService(); service.saveCar(car); request.getSession().setAttribute("carName", sname); request.getSession().setAttribute("carPrice", sprice); page = CAR_SAVED_VIEW; } else { page = WRONG_PARAMS_VIEW; } } response.sendRedirect(page); } } ``` 該 servlet 位于`com.zetcode.web`包中。 ```java private static final String READ_CAR_BY_ID_VIEW = "readCarId.jsp"; private static final String SHOW_CAR_VIEW = "showCar.jsp"; private static final String READ_CAR_VIEW = "readCar.jsp"; ... ``` 這些是我們的應用中使用的各種視圖。 ```java private static final String LIST_CARS_ACTION = "listcars"; private static final String READ_CAR_BY_ID_ACTION = "readbyid"; private static final String READ_CAR_ACTION = "readcar"; ... ``` 這些是應用的各種動作。 例如,`READ_CAR_ACTION`顯示的視圖包含一個表單,用戶可以在其中輸入新車的詳細信息。 ```java if (LIST_CARS_ACTION.equals(actionName)) { ICarsService service = new CarsService(); request.setAttribute("carList", service.findAllCars()); page = ALL_CARS_VIEW; } ``` 對于`LIST_CARS_ACTION`,我們創建一個`CarsService`對象。 我們調用`findAllCars()`服務方法,并將結果設置為`carList`屬性。 然后,控制器 Servlet 指向`ALL_CARS_VIEW`。 ```java if (VIEW_CAR_ACTION.equals(actionName)) { String sid = request.getParameter("carId"); if (ValidateParameter.validateId(sid)) { ICarsService service = new CarsService(); Long carId = Long.valueOf(sid); request.setAttribute("returnedCar", service.findCar(carId)); page = SHOW_CAR_VIEW; } else { page = WRONG_PARAMS_VIEW; } } ``` 為了查看一輛汽車,我們從`request`參數中獲得了汽車的 ID。 該值使用`ValidateParameter.validateId()`工具方法進行驗證。 (該值不能為`null`,為空,并且必須為數字。)如果參數無效,則控制器導航至`WRONG_PARAMS_VIEW`。 `findCar()`嘗試從數據庫中檢索汽車。 返回的汽車將插入`returnedCar`屬性,該屬性隨后會在`showCar.jsp`頁面中獲取。 ```java if (ValidateParameter.validateName(sname) && ValidateParameter.validatePrice(sprice)) { Car car = new Car(); car.setName(sname); car.setPrice(Integer.valueOf(sprice)); ICarsService service = new CarsService(); service.saveCar(car); request.getSession().setAttribute("carName", sname); request.getSession().setAttribute("carPrice", sprice); page = CAR_SAVED_VIEW; } else { page = WRONG_PARAMS_VIEW; } ``` 該代碼位于`doPost()`方法中。 保存新車時,我們有兩個參數:汽車的名稱和價格。 該 ID 由 Derby 自動創建。 驗證參數,并創建一個新的`Car`對象并填充參數。 `saveCar()`將汽車對象保存到數據庫中。 汽車的名稱將傳遞到`CAR_SAVED_VIEW`,以便向用戶創建消息。 由于我們在`doPost()`方法中使用了重定向,因此我們將汽車的名稱及其價格放入會話對象; 進行重定向操作后,我們會從原始請求中刪除數據。 ```java response.sendRedirect(page); ``` 遵循發布/重定向/獲取模式,我們將重定向到`doPost()`方法中的視圖。 這樣可以防止提交多個表單。 (例如,我們可能不小心多次添加了汽車)。 ![Displaying all cars](https://img.kancloud.cn/17/ec/17ecfef6e9d542590f8e9ef9017df748_504x588.jpg) 圖:顯示所有汽車 在本教程中,我們創建了一個簡單的 Web 應用框架,用于管理汽車對象。 數據已保存在 Derby 數據庫中。 該應用分為四層。 我們已經使用 DAO 模式進行數據訪問。 您可以在 ZetCode 的 [Derby 教程](/db/apachederbytutorial)中找到有關 Derby 的更多信息。 在[中顯示數據網格中的數據](/articles/easyuidatagrid/)教程中,我們展示了如何在 EasyUI datagrid 控件中顯示來自 Derby 數據庫的數據。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看