伺服器端程式設計完整例項
專案結構
下面對每個包對應的邏輯和功能做簡要說明
com.bupt.dao:裡面是進行資料庫操作的相關介面。介面相當於一種規範,增加了系統的可測試性和健壯性,無論之後的daoImpl中的實現程式碼如何改變,只要介面不改變就不會影響程式的執行,降低了程式的耦合度,便於進行單元測試。
com.bupt.dao.impl:裡面是上面資料庫相關操作介面的實現類。
com.bupt.entity:裡面是要在資料庫中操作的物件實體,比如使用者物件,可以看作資料庫中的一張表,使用者表或是地址表之類的。他們在資料庫中所在的表不同,但是都有一個主鍵id(userId,addressId...),所以他們要統一的繼承抽象類IdEntity,這個類裡只有一個id,專案的邏輯更加清晰,程式碼更少。
com.bupt.service:裡面是根據專案的要求不同進行的一些服務操作,比如判斷使用者表中有沒有重複的使用者名稱之類的。儘管UserDaoImpl中,我們也可以寫相應的實現方法,但是這個服務層是有存在的意義的,如果沒有這個服務層,那麼servlet就要直接呼叫UserDaoImpl中的方法,但是UserDaoImpl中的方法只是執行了資料庫的查詢或是插入操作,如果有更加複雜的操作,那麼就無法滿足,強行滿足要求就要在impl類中寫大量複雜的實現,而且servlet中就要多次呼叫daoImpl中的方法,導致servlet無法明顯的體現出自身要執行的功能,這樣模糊的servlet可能就要導致客戶端執行一個註冊功能就要多次請求不同的servlet來完成,所以service層的存在使得整個專案的層次更加清晰。
com.bupt.servlet:裡面是客戶端進行相應請求要訪問的servlet類。
com.bupt.util:裡面是連線資料庫所需的ConnectionFactory工廠類,其中的dburl等引數是從配置檔案dbconfig.properties中讀取的。需要jdbc的jar包,複製進來並引用。
下面貼程式碼
UsreDao
package com.bupt.dao; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import com.bupt.entity.User; //資料庫中使用者表相關的操作介面 public interface UserDao { public void insert(Connection conn, User user) throws SQLException; public ResultSet get(Connection conn, User user) throws SQLException; }
UserDaoImpl
package com.bupt.dao.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.bupt.dao.UserDao;
import com.bupt.entity.User;
//資料庫中有關使用者表的介面實現
public class UserDaoImpl implements UserDao {
@Override
public void insert(Connection conn, User user) throws SQLException {
String sql = "INSERT INTO user(username,password,email) VALUES (?,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, user.getUserName());
ps.setString(2, user.getPassword());
ps.setString(3, user.getEmail());
ps.execute();
}
@Override
public ResultSet get(Connection conn, User user) throws SQLException {
String sql = "SELECT * FORM user WHERE username=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, user.getUserName());
return ps.executeQuery();
}
}
IdEntity
package com.bupt.entity;
//Id實體抽象類,其他實體類的父類
public abstract class IdEntity {
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
User
package com.bupt.entity;
//使用者實體,因為之後每個實體在資料表中都有主鍵id屬性,所以他們都繼承了IdEntity抽象類
public class User extends IdEntity {
private String userName;
private String password;
private String email;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
CheckUserPermissionService
package com.bupt.service;
import java.sql.Connection;
import java.sql.ResultSet;
import com.bupt.dao.UserDao;
import com.bupt.dao.impl.UserDaoImpl;
import com.bupt.entity.User;
import com.bupt.util.ConnectionFactory;
//驗證使用者登入是否成功
//有三個不同的返回情況
//return 1:登入成功
//return 2:密碼錯誤
//return 3:無此使用者
public class CheckUserPermissionService {
public static int checkPermission(User user) {
Connection conn = null;
boolean hasUser = false;
try {
UserDao us = new UserDaoImpl();
conn = ConnectionFactory.getInstance().makeConnection();
conn.setAutoCommit(false);
ResultSet rs = us.get(conn, user);
if (rs.next()) {
hasUser = true;
if(user.getPassword().equals(rs.getString("password"))){
return 1;
}
}
if(hasUser == true){
return 2;
}
} catch (Exception e) {
e.printStackTrace();
try {
conn.rollback();
} catch (Exception e2) {
e2.printStackTrace();
}
} finally {
try {
conn.close();
} catch (Exception e3) {
e3.printStackTrace();
}
}
return 3;
}
}
CheckUserService
package com.bupt.service;
import java.sql.Connection;
import java.sql.ResultSet;
import com.bupt.dao.UserDao;
import com.bupt.dao.impl.UserDaoImpl;
import com.bupt.entity.User;
import com.bupt.util.ConnectionFactory;
//查詢資料庫使用者表中有沒有相同的使用者名稱
public class CheckUserService {
public static boolean check(User user) {
Connection conn = null;
try {
UserDao us = new UserDaoImpl();
conn = ConnectionFactory.getInstance().makeConnection();
conn.setAutoCommit(false);
ResultSet rs = us.get(conn, user);
if (rs.next()) {
return true;
}
} catch (Exception e) {
e.printStackTrace();
try {
conn.rollback();
} catch (Exception e2) {
e2.printStackTrace();
}
} finally {
try {
conn.close();
} catch (Exception e3) {
e3.printStackTrace();
}
}
return false;
}
}
InsertUserService
package com.bupt.service;
import java.sql.Connection;
import com.bupt.dao.UserDao;
import com.bupt.dao.impl.UserDaoImpl;
import com.bupt.entity.User;
import com.bupt.util.ConnectionFactory;
//將建立好的實體使用者插入到資料庫中
/*
* 儘管UserDaoImpl中也有相應的插入資料的實現方法,但是這個服務類有存在的意義,
* 如果沒有這個服務類,那麼servlet就要直接呼叫UserDaoImpl中的方法,
* 但是UserDaoImpl中的方法只是執行了資料庫的查詢或是插入操作,如果有更加複雜的操作,那麼就無法滿足,
* servlet中就要多次呼叫daoImpl中的方法,導致servlet無法明顯的體現出自身要執行的功能,
* 這樣模糊的servlet可能就要導致客戶端執行一個註冊功能就要多次請求不同的servlet來完成,
* 所以service層使得整個專案的層次更加清晰
*/
public class InsertUserService {
public static void insert(User user) {
Connection conn = null;
try {
UserDao us = new UserDaoImpl();
conn = ConnectionFactory.getInstance().makeConnection();
conn.setAutoCommit(false);
us.insert(conn, user);
System.out.println("插入新使用者成功");
} catch (Exception e) {
e.printStackTrace();
try {
conn.rollback();
} catch (Exception e2) {
e2.printStackTrace();
}
} finally {
try {
conn.close();
} catch (Exception e3) {
e3.printStackTrace();
}
}
}
}
LoginServlet
package com.bupt.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.bupt.entity.User;
import com.bupt.service.CheckUserPermissionService;
//客戶端進行登入時要請求的servlet
//url-pattern: /login
//login success:登入成功
//password error:密碼錯誤
//no user:無此使用者
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 5290609484927130100L;
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String userName = req.getParameter("username");
String password = req.getParameter("password");
User user = new User();
user.setUserName(userName);
user.setPassword(password);
int result = CheckUserPermissionService.checkPermission(user);
PrintWriter pw = resp.getWriter();
if (result == 1) {
pw.print("login success");
} else if (result == 2) {
pw.print("password error");
} else {
pw.print("no user");
}
pw.close();
}
}
RegisterServlet
package com.bupt.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.bupt.entity.User;
import com.bupt.service.CheckUserService;
import com.bupt.service.InsertUserService;
//客戶端進行註冊時要請求的servlet
//url-pattern: /register
//"register success":註冊成功
//"username repeat":使用者名稱重複
public class RegisterServlet extends HttpServlet {
private static final long serialVersionUID = 3971678149369992198L;
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String userName = req.getParameter("username");
String password = req.getParameter("password");
String email = req.getParameter("email");
User user = new User();
user.setUserName(userName);
user.setPassword(password);
user.setEmail(email);
boolean flag = CheckUserService.check(user);
PrintWriter pw = resp.getWriter();
if (flag == false) {
InsertUserService.insert(user);
pw.println("register success");
} else {
pw.print("username repeat");
}
pw.close();
}
}
ConnectionFactory
package com.bupt.util;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;
//提供資料庫連線的連線工廠類,driver,dburl,user,password等屬性由dbconfig.properties得到
public class ConnectionFactory {
private static String driver;
private static String dburl;
private static String user;
private static String password;
private static final ConnectionFactory factory = new ConnectionFactory();
private Connection conn;
static {
Properties prop = new Properties();
try {
InputStream inputStream = ConnectionFactory.class.getClassLoader()
.getResourceAsStream("dbconfig.properties");
prop.load(inputStream);
} catch (Exception e) {
e.printStackTrace();
}
driver = prop.getProperty("driver");
dburl = prop.getProperty("dburl");
user = prop.getProperty("user");
password = prop.getProperty("password");
}
public ConnectionFactory() {
}
public static ConnectionFactory getInstance() {
return factory;
}
public Connection makeConnection() {
try {
Class.forName(driver);
conn = DriverManager.getConnection(dburl, user, password);
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
}
dbconfig.properties
driver=com.mysql.jdbc.Driver
dburl=jdbc\:mysql\://localhost\:3306/study?useSSL=false
user=root
password=root
web.xml
<?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_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>Study</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>
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.bupt.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>register</servlet-name>
<servlet-class>com.bupt.servlet.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>register</servlet-name>
<url-pattern>/register</url-pattern>
</servlet-mapping>
</web-app>