引出
1.為什么建那么多層,dao,service…
2.項目設(shè)計分層初步;
3.本文以養(yǎng)老院老人信息管理、招聘應(yīng)聘控制臺項目為例;
git倉庫地址
DAO層—和數(shù)據(jù)庫交互
1.通過IO流存儲到dat文件
IO流及其項目應(yīng)用初步
(1)類需要實現(xiàn)Serializable序列化接口
package com.tianju.older.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
import java.util.Date;
import java.util.Objects;
@Setter@Getter
@AllArgsConstructor
@NoArgsConstructor
public class Older implements Serializable { // 實現(xiàn)序列化接口
private String id;
private String name;
private Integer age;
private Date inDate;
@Override
public String toString() {
return "Older[" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
", inDate=" + inDate +
']';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Older older = (Older) o;
return Objects.equals(id, older.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
(2)dao層的接口和實現(xiàn)分離
接口:
package com.tianju.older.dao;
import com.tianju.older.entity.Older;
import java.util.List;
/**
* Older的dao類
*/
public interface IOlderDao {
// 保存老人信息
void save(Older older);
// 刪除老人信息
void delete(Older older);
// 更新老人信息
void update(Older older);
// 根據(jù)id找老人信息
Older findById(String id);
// 找到全部老人信息
List<Older> findAll();
// 保存到文件的方法
void saveToFile();
// 從文件中讀取成老人類的方法
List<Older> loadFromFile();
}
實現(xiàn):
package com.tianju.older.dao.impl;
import com.tianju.older.dao.IOlderDao;
import com.tianju.older.entity.Older;
import com.tianju.older.exception.NotFoundOlderException;
import com.tianju.older.util.Config;
import org.apache.log4j.Logger;
import java.io.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
public class OlderDaoImpl implements IOlderDao {
List<Older> list = null;
// 如果讀取到的loadFromFiLe不為null,則賦值給list;
// 否則new 出來
public OlderDaoImpl() {
List<Older> olders = loadFromFile();
if (Objects.isNull(olders)){
list = new ArrayList<>(20);
}else {
list = olders;
}
}
@Override
public void save(Older older) {
list.add(older);
Logger.getLogger(this.getClass()).info("addOlder: " + older);
saveToFile();
}
@Override
public void delete(Older older) {
// 先看能不能找到
Older find = findById(older.getId());
// 如果找到,刪除;沒找到,拋出異常,并記錄日志
if (Objects.isNull(find)){
throw new NotFoundOlderException("404異常,該老人信息不存在,未刪除");
}
Logger.getLogger(this.getClass()).info("deleteOlder: " + find);
list.remove(older);
saveToFile(); // 文件更新
}
@Override
public void update(Older older) {
// 找到index,用set方法更新
Older find = findById(older.getId()); // 根據(jù)ID定位老人
if (Objects.isNull(find)){
throw new NotFoundOlderException("404異常,該老人信息不存在,無法修改");
}
// 記錄日志信息
Logger.getLogger(this.getClass()).info("beforeUpdate: " + find);
int index = list.indexOf(find);
list.set(index,older);
Logger.getLogger(this.getClass()).info("afterUpdate: "+older);
// 刷新文件
saveToFile();
}
@Override
public Older findById(String id) {
Older find = null;
Iterator<Older> it = list.iterator();
while (it.hasNext()){
Older older = it.next();
if (older.getId().equals(id)){
find = older;
break;
}
}
return find;
}
@Override
public List<Older> findAll() {
return list;
}
@Override
public void saveToFile() {
// 從內(nèi)存寫入硬盤,輸出
try {
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("D:\\Myprogram\\idea-workspace\\Older_v2.6\\Older_v2.6\\src\\com\\woniuxy\\older\\resources\\older.dat")
);
out.writeObject(list);
Logger.getLogger(OlderDaoImpl.class).info("save保存"+list.size()+"信息");
out.flush();
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public List<Older> loadFromFile() {
// 從硬盤讀入內(nèi)存,輸入
List<Older> loadList = null;
try {
ObjectInputStream in = new ObjectInputStream(
new FileInputStream(Config.getDatPath())
);
loadList = (List<Older>) in.readObject();
in.close();
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException(e);
}
return loadList;
}
}
2.通過JDBC存儲到數(shù)據(jù)庫
參考下面文章:
java連接SQL數(shù)據(jù)庫 & 單例封裝數(shù)據(jù)庫文章來源:http://www.zghlxwxcb.cn/news/detail-696302.html
【測試】用junit進(jìn)行測試:@Test注解
Service層—處理業(yè)務(wù)
1.項目設(shè)計分層初步
引入前端后,MVC模型:視圖,模型,控制器
2.service處理業(yè)務(wù)相關(guān)
一個求職者和應(yīng)聘者登陸和注冊的業(yè)務(wù)接口
package com.qianbaidu.recruit.service;
import com.qianbaidu.recruit.entity.Boss;
import com.qianbaidu.recruit.entity.Emp;
/**
* 用戶登陸的服務(wù)接口
*/
public interface ILoginService {
boolean login(String role);
boolean sign(String role);
// 返回登陸后的id,默認(rèn)的id為-1,或者null
// 0老板,1應(yīng)聘者;-1,未登錄成功,登陸成功返回id
String[] execute();
}
3.和UI層以及dao層進(jìn)行交互
UI層界面—控制臺,單例模式
1.創(chuàng)建單例的方法
創(chuàng)建單例的方法
2.頁面的實現(xiàn)
用枚舉的方式實現(xiàn)單例
package com.qianbaidu.recruit.ui;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
public enum ApplicantMenuUI {
APPLY_UI;
private Scanner sc;
private ApplicantMenuUI(){
sc = new Scanner(System.in);
}
// 主界面 公司查詢,信息修改,職位查詢,企業(yè)打分
public String appExecuteUI(){
System.out.println("------------------歡迎您進(jìn)入 眾里尋他 招聘信息網(wǎng)站的 應(yīng)聘者主界面------------------------");
System.out.println("1.進(jìn)行個人信息修改");
System.out.println("2.進(jìn)行公司的查詢");
System.out.println("3.進(jìn)行職位的查詢");
System.out.println("4.查看個人申請記錄");
System.out.println("5.對企業(yè)進(jìn)行評分");
System.out.println("0.返回上一級界面");
return sc.nextLine();
}
}
Exception層----異常的處理
(1)自定義異?!脩舻顷懏惓?/p>
package com.qianbaidu.recruit.exception;
/**
* 402異常,用戶登陸異常
*/
public class LoginIllegalException extends RuntimeException{
public LoginIllegalException(String message) {
super(message);
}
}
(2)使用異常類進(jìn)行登陸驗證
private Emp loginEmp(){
// 用戶名錯誤
String[] loginInput = LoginMenu.loginUI("1");//(企業(yè)0,求職者1)
if (dao.findEmpByLoginName(loginInput[0])==null){
throw new LoginNameNotFoundException("404異常,用戶名"+loginInput[1]+"不存在,請注冊");
}
Emp loginEmpLoginNameTrue = dao.findEmpByLoginName(loginInput[0]);
// 用戶名/密碼錯誤
if (dao.findEmpLoginNameAndPassword(loginInput[0],loginInput[1])==null){
throw new LoginIllegalException("405異常,用戶名|密碼錯誤,請重新輸入+" + loginEmpLoginNameTrue.getUsername());
}
Emp loginEmp = dao.findEmpLoginNameAndPassword(loginInput[0],loginInput[1]);
Logger.getLogger(this.getClass()).info("應(yīng)聘者用戶 "+loginEmp.getUsername()+" 登陸");
return loginEmp;
}
Test測試層----dao和service可測
1.dao的測試
Dao層的測試,用junit4
package com.tianju.older.test;
import com.tianju.older.dao.IOlderDao;
import com.tianju.older.dao.impl.OlderDaoImpl;
import com.tianju.older.entity.Older;
import org.junit.Test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
/**
* dao的測試類
*/
public class OlderDaoImplTest {
private IOlderDao dao = new OlderDaoImpl();
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd");
@Test
public void save() throws ParseException {
dao.save(new Older("1", "小王", 28, sdf.parse("2023-04-07")));
dao.save(new Older("2", "小張", 26, sdf.parse("2023-05-07")));
dao.save(new Older("3", "小李", 24, sdf.parse("2021-06-07")));
dao.save(new Older("3", "小鵬", 24, sdf.parse("2022-04-10")));
System.out.println(dao.findAll());
}
@Test
public void loadFromFile() {
System.out.println(dao.loadFromFile());
System.out.println(dao.findAll());
}
@Test
public void delete() {
dao.loadFromFile();
System.out.println(dao.findAll());
// 刪除
dao.delete(new Older("2",null,null,null));
// 刪除是否保存成功
System.out.println(dao.loadFromFile());
}
}
2.service結(jié)合UI測試
如果涉及到控制臺的輸入,則不能用junit
package com.qianbaidu.recruit.test;
import com.qianbaidu.recruit.dao.IApplicantDao;
import com.qianbaidu.recruit.dao.impl.ApplicantDaoImpl;
import com.qianbaidu.recruit.service.IApplicantService;
import com.qianbaidu.recruit.service.impl.ApplicantServiceImpl;
public class ApplyMainTest {
public static void main(String[] args) {
IApplicantService ias = new ApplicantServiceImpl();
while (true){
ias.execute(1);
}
}
}
resource層-----配置文件,數(shù)據(jù)文件
可以參考下面博客:
IO流及其項目應(yīng)用初步
在本控制臺項目中,resources文件夾包括以下文件
- 戶名密碼存儲的文件,login.properties文件;
- log4j日志記錄文檔,log.log文件;
- 保存數(shù)據(jù)信息的文件,older.dat文件;
項目的日志—log4j
日志是文件,記錄一些信息。記錄重要的,登錄信息,操作,異常信息。
1.日志的級別
DEBUG: 項目開發(fā)人員的測試
INFO: 一般信息(開發(fā)人員,其他)
WARN: 警告(開發(fā)人員警告使用者)
ERROR: 系統(tǒng)比較嚴(yán)重問題
FATAL: 非常嚴(yán)重的問題
控制的日志可見性
2.日志的配置和使用
其中的log4j配置文件目錄和內(nèi)容如下:
配置文件內(nèi)容:
log4j.rootLogger=DEBUG,Console,F
#顯示在控制臺
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=[%p],%d{yyyy-MM-dd HH:mm:ss},[%t],%rms,[%m]%n
#在文件輸出
log4j.appender.F=org.apache.log4j.RollingFileAppender
log4j.appender.F.File=d:\\log.log
log4j.appender.F.layout=org.apache.log4j.PatternLayout
log4j.appender.F.layout.ConversionPattern=[%p],%d{yyyy-MM-dd HH:mm:ss},[%t],%rms,[%m]%n
util層—工具,DbUtil,常量
1.枚舉的使用
枚舉類型作用
替代常量的。編碼規(guī)范: 魔鬼常量
if(choice == 1)
switch(a){
case 1:
? break;
}
枚舉的定義代碼:
package com.tianju.older.util;
/**
* 業(yè)務(wù)的選擇
* 登陸后選擇,1.錄入老人信息;2.修改老人信息;3.刪除老人信息;4.查詢老人信息;0.返回登陸界面
*/
public enum Choice {
ADD_MES,UPDATE_MES,DELETE_MES,QUERY_ALL,BACK_LOGIN;
/**
* 根據(jù)客戶輸入的數(shù)字轉(zhuǎn)換成枚舉類型
* @param ch 輸入的數(shù)字
* @return 轉(zhuǎn)換成的枚舉類型
*/
public static Choice get(String ch){
if (ch.equals("1")){
return ADD_MES;
}else if (ch.equals("2")){
return UPDATE_MES;
} else if (ch.equals("3")){
return DELETE_MES;
} else if (ch.equals("4")){
return QUERY_ALL;
}else {
return BACK_LOGIN;
}
}
}
使用枚舉類型代替魔鬼常量:
比如在頁面里讓用戶在控制臺輸入,0~4進(jìn)行操作選擇
public static String welcome(){
System.out.println("-------------------歡迎進(jìn)入老人信息管理系統(tǒng)-------------------");
// 登陸后選擇,1.錄入老人信息;2.修改老人信息;3.刪除老人信息;4.查詢老人信息;0.返回登陸界面
System.out.println("1.錄入老人信息");
System.out.println("2.修改老人信息");
System.out.println("3.刪除老人信息");
System.out.println("4.查詢老人信息");
System.out.println("0.返回登陸界面");
System.out.println("-----------------------------------------");
System.out.print("請輸入選擇:");
// 正則表達(dá)式判斷
String in = sc.nextLine();
String regex = "[0-4]{1}";
if (!in.matches(regex)){
System.out.println("輸入錯誤,請輸入0-4之間的數(shù)字");
}
return in;
}
然后在這里用枚舉代替魔鬼常量,讓代碼可讀性增強(qiáng);
private void welcome(){
boolean isContinue = true;
while (isContinue) {
String ch = OlderMenu.welcome();
Choice c = Choice.get(ch);
switch (c){
case ADD_MES:
addOlder();
break;
case UPDATE_MES:
updateOlder();
break;
case DELETE_MES:
deleteOlder();
break;
case QUERY_ALL:
findAll();
break;
case BACK_LOGIN:
isContinue = false;
System.out.println("------------再見,歡迎再次登陸------------");
break;
}
}
}
2.常量的定義
比如下面,用數(shù)字0~3來表示公司規(guī)模為1-20人,20-100人,100-500人,以及大于500人這幾種公司規(guī)模
package com.qianbaidu.recruit.util;
import com.qianbaidu.recruit.exception.InputIllegalException;
public class Constance {
public final static String COMPANY_LESS20 = "1~20人";
public final static String COMPANY_LESS100 = "20~100人";
public final static String COMPANY_LESS500 = "100~500人";
public final static String COMPANY_MORE500 = "大于500人";
public static String showCompanySize(int size){
if (size==0){
return COMPANY_LESS20;
}else if(size==1){
return COMPANY_LESS100;
}else if (size==2){
return COMPANY_LESS500;
}else if (size==3){
return COMPANY_MORE500;
}
return null;
}
}
在公司信息的實體類的toString方法中調(diào)用showCompanySize()方法把數(shù)字轉(zhuǎn)成常量對應(yīng)的中文;
@Override
public String toString() {
return "\nCompany{" +
"id=" + id +
", name='" + name + '\'' +
", size=" + Constance.showCompanySize(size) +
", address='" + address + '\'' +
", type='" + type + '\'' +
", web='" + web + '\'' +
", phone='" + phone + '\'' +
", person='" + person + '\'' +
", desc='" + desc + '\'' +
", rate=" + rate +
", rates=" + rates +
'}';
}
3.DbUtil
參考下面文章:
java連接SQL數(shù)據(jù)庫 & 單例封裝數(shù)據(jù)庫
總結(jié)
1.關(guān)于控制臺項目中使用到Java基礎(chǔ)知識;
2.實體類和dao層,增刪改查CRUD分離,從IO流到JDBC,SQL語句;
3.dao層和service層,dao層和數(shù)據(jù)庫交互,service層處理業(yè)務(wù),初步了解程序設(shè)計思想;
4.測試:dao層和service層的方法要可測,@Test注解,涉及控制臺輸入不能用@Test;
5.控制臺的UI層處理控制臺的輸入,學(xué)習(xí)單例創(chuàng)建UI類的方法;
6.異常類,用自定義異常處理業(yè)務(wù),初步學(xué)習(xí)Java的異常機(jī)制;
7.配置文件,resources層,用配置文件實現(xiàn)程序解耦,初步了解程序設(shè)計思想;
8.日志文件:log4j的配置,軟件要有日志,日志的級別;
9.工具類:枚舉類的使用,常量的定義,JDBC封裝方式,創(chuàng)建單例的三種方法;文章來源地址http://www.zghlxwxcb.cn/news/detail-696302.html
到了這里,關(guān)于Java基礎(chǔ)(項目1)——項目設(shè)計分層 & dao + service + test +ui + exception + log + util的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!