四,手寫SpringMVC框架,業務層-什麼是耦合/依賴?如何解決

来源:https://www.cnblogs.com/lijili/archive/2022/08/17/16596640.html
-Advertisement-
Play Games

4. 業務層 4.1 MVC模型 MVC:Model(模型),View(視圖),Controller(控制器) 視圖層:用於做數據的展示以及和用戶交互的一個界面=>jsp 控制層:能夠接受客戶端的請求並且進行請求轉發,具體的業務功能還是需要藉助模型層組件來完成。CoreServlet => Disp ...


4. 業務層

4.1 MVC模型

MVCModel(模型),View(視圖),Controller(控制器)

視圖層:用於做數據的展示以及和用戶交互的一個界面=>jsp

控制層:能夠接受客戶端的請求並且進行請求轉發,具體的業務功能還是需要藉助模型層組件來完成。CoreServlet  => DispacherServlet + EmpController

模型層:模型分為很多種:

1) 存值的值對象: POJO/VO(value object)/entity/bean  -> Emp

2有數據訪問對象:DAO---數據訪問對象:xxxDao

3) 有業務模型對象:BO,業務對象 比如:xxxService

4) 數據傳輸對象:DTO data transfer object

 

4.1 什麼是業務對象

 

 

4.2 區分業務對象和數據訪問對象

4.2.1 單精度方法

DAO中的方法都是單精度方法 或者稱之為細粒度方法。

什麼叫單精度?一個方法只考慮一個操作,比如,添加,那就是insert操作。查詢那就是select操作。

 

4.2.2 BO也就是Service層屬於業務方法

BO中的方法屬於業務方法,但實際的業務是比較複雜的,因此業務方法的粒度是比較粗的

比如:註冊這個功能屬於業務功能,也就是說註冊這個方法屬於業務方法。

那麼在這個業務方法中包含了多少個DAO方法呢,也就是說註冊這個業務功能需要通過調用多個DAO方法的組合調用才能完成註冊功能。

 

4.2.3 註冊的功能步驟:

1、檢查用戶名是否已經被註冊—DAO中的select操作。

2、向用戶表新增一條新用戶記錄—DAOinsert操作。

3、向用戶積分表新增一條記錄(新用戶預設初始化積分假如是100分)--DAO中的insert操作

4、向系統消息表新增一條記錄(某某新用戶註冊了,需要根據通訊錄信息向他的聯繫人推送消息)--DAO中的insert操作。

5、向系統日誌表新增一條記錄(某用戶在某IP在某年某月某日某時某分某秒註冊)--DAO中的insert操作。

 

4.3 代碼的編寫(mymvc4)

 

 

 

 

4.4 新建IEmpDao & EmpDaoImpl

 

 

 

 

 

 

 

 

 

 

4.5 新建IEmpService & EmpServiceImpl,寫一個reg方法

 

 

 

 

 

 

 

 

 

4.6 EmpController中的代碼

package com.hy.controller;

 

import com.hy.service.IEmpService;

import com.hy.service.impl.EmpServiceImpl;

 

public class EmpController {

private IEmpService empService = new EmpServiceImpl();

 

public void add(String ename,String pwd) {

try {

boolean flag = empService.reg(ename, pwd);

} catch (Exception e) {

e.printStackTrace();

}

}

 

public String index() {

System.out.println("EmpController...index");

return "forward:/WEB-INF/emp/index.jsp";

}

 

public String login(String ename,String pwd) {

System.out.printf("EmpControllerlogin方法獲取的參數值ename=%s,pwd=%s",ename,pwd);

return "redirect:emp.do?ac=index";

}

 

public String delete(Integer eid) {

if(eid !=null ) {

System.out.println("EmpController eid=="+eid);

//empDao.delete(eid);

return "forward:xxx";

}

return "forward:error.xxx";

}

}

5. 什麼耦合/依賴

耦合/依賴 :依賴指的是誰離不開誰,這叫依賴。比如:你離不開你女朋友。你依賴你女朋友

在我們系統當中的每個層之間,層與層之間也存在依賴。比如:Controller層必須依賴Service層,例如:現在將ServiceEmpServiceImpl刪除了,然後EmpController層就會報錯。

同樣,Service層依賴Dao層。

 

 

 

 

 

依賴指的是 某某某 離不開 某某某

在軟體系統中,層與層之間是存在依賴的。我們也稱之為耦合。

我們系統架構或是設計的一個原則就是:高內聚 低耦合。

層內部的組成應該是高度聚合的,而層與層之間的關係應該是低耦合的。

 

而所謂的低耦合,就是我們熟稱的炮友。

 

我想做到的是什麼??刪除EmpServiceImpl  EmpController不報錯,EmpController中有new EmpServiceImpl( ) ; 這麼new的會就表示和下層的EmpServiceImpl有關係了。

 

 

 

 

 

 

 

 

6. 如何解決耦合和依賴?

IOC-反轉控制/ DI-依賴註入

6.1 第一步,將=new 刪掉

 

 

 

 

 

 

 

 

6.2 第二步,解決空指針的問題

6.2.1 編寫applicationContext.xml配置文件,

applicationContext.xml再寫兩行配置文件,在當前的整個配置文件中配置了三個bean,這三個bean就是對應了三個組件。下一步,計劃在系統啟動的時候它就會把這三個組件準備好,放在一個容器裡面,誰需要的時候就給誰用

<?xml version="1.0" encoding="UTF-8"?>

 

<beans>

<!--

這個bean標簽的作用是,id中的值,要和將來和ServletPath

中路徑的名做對應,emp對應的就要EmpController這個類來處理。

 -->

<bean id="emp" class="com.hy.controller.EmpController"/>

 

<bean id="empService" class="com.hy.service.impl.EmpServiceImpl"/>

 

<bean id="empDao" class="com.hy.dao.impl.EmpDaoImpl"/>

</beans>

 

6.2.2 新建一個介面 BeanFactory & 實現類ClassPathXMLApplicationContext

 

 

 

 

 

 

 

 

 

6.2.3 ClassPathXMLApplicationContext的代碼

package com.hy.io;

 

import java.io.IOException;

import java.io.InputStream;

import java.util.concurrent.ConcurrentHashMap;

 

import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import javax.xml.parsers.ParserConfigurationException;

 

import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.w3c.dom.Node;

import org.w3c.dom.NodeList;

import org.xml.sax.SAXException;

 

public class ClassPathXMLApplicationContext implements BeanFactory {

private ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();

 

// 在預設構造方法中載入配置文件

public ClassPathXMLApplicationContext() {

 

try {

InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("applicationContext.xml");

 

// 1,創建DocumentBuilderFactory工廠對象

DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();

 

// 2,創建DocumentBuilder對象

DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();

 

// 3,得到Document對象( 註意導入org.w3c.dom包中的)

Document document = documentBuilder.parse(inputStream);

 

// 4,獲得所有的Bean標簽

NodeList nodeList = document.getElementsByTagName("bean");

 

for (int i = 0, len = nodeList.getLength(); i < len; i++) {

Node node = nodeList.item(i);

 

System.out.println(node.getNodeType() );//1,1,1

 

if( node.getNodeType() == node.ELEMENT_NODE) {

Element element = (Element)node;

String id = element.getAttribute("id");

String className = element.getAttribute("class");

 

boolean flag = map.containsKey(id);

 

if(flag == true)

return;

 

Class clazz = Class.forName(className);

Object o = clazz.newInstance();

 

map.put(id, o);

}

}

 

} catch (ParserConfigurationException e) {

e.printStackTrace();

} catch (SAXException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

} catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (InstantiationException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

}

}

 

@Override

public Object getBean(String id) {

return map.get(id);

}

 

public static void main(String[] args) {

ClassPathXMLApplicationContext applicationContext = new ClassPathXMLApplicationContext();

}

}

 

運行main方法測試一下。

 

6.2.4 回到DispatcherServlet修改代碼

package com.hy.servlet;

 

import java.io.IOException;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import java.lang.reflect.Parameter;

 

import javax.servlet.ServletConfig;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

import com.hy.io.BeanFactory;

import com.hy.io.ClassPathXMLApplicationContext;

import com.hy.utils.StringUtil;

 

@WebServlet("*.do")

public class DispatcherServlet extends HttpServlet {

private BeanFactory beanFactory;

 

public DispatcherServlet() {

}

 

@Override

public void init(ServletConfig config) throws ServletException {

super.init(config);

beanFactory = new ClassPathXMLApplicationContext();

}

 

@Override

protected void service(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

// 設置編碼

request.setCharacterEncoding("UTF-8");

response.setCharacterEncoding("UTF-8");

response.setContentType("text/html;charset=UTF-8");

 

// 假設url是: http://localhost:8080/mymvc2/hello.do

// ServletPathServlet的訪問路徑: /hello.do

// 思路是:

// 1步: /hello.do -> hello 或者 /book.do -> book

// 2步: hello -> HelloController 或者 book -> BookController

String servletPath = request.getServletPath(); // /hello.do

int lastDotIndex = servletPath.lastIndexOf(".do");

servletPath = servletPath.substring(1, lastDotIndex); // hello

 

// 通過ServletPath獲取對應的Controller對象

// Object xxxController = map.get(servletPath);

Object xxxController = beanFactory.getBean(servletPath);

 

String ac = request.getParameter("ac");

System.out.println("=======ac ===" + ac + "======");

if (StringUtil.isEmpty(ac))

ac = "index";

 

String methodReturnStr = null;

try {

// 這裡只能try...catch異常,因為在重寫的方法里,不能拋出比父類更大的異常

Method[] methods = xxxController.getClass().getDeclaredMethods();

 

if (methods != null) {

for (Method method : methods) {

if (ac.equals(method.getName())) {

// 1,統一獲取請求參數

// 1.1 獲取當前方法的參數,返回參數數組

Parameter[] parameters = method.getParameters();

// 1.2 有幾個參數就需要準備同等容量的Object類型的數組。這個數組用來存放參數的值得

Object[] parameterValues = new Object[parameters.length];

 

for (int i = 0, len = parameters.length; i < len; i++) {

Parameter parameter = parameters[i];

 

// 1.3 從請求中獲取參數的值

String parameterValue = request.getParameter(parameter.getName());

/**

 * 註意,這裡沒有考慮 覆選框的情況,因為覆選框name相同,

 * 打了好幾個勾,一提交,返回給我們值的是一個數組 獲取的方法:

 * request.getParameterValues(name);

 */

 

// 1.5 EmpControllerdelete方法的參數需要的是一個Integer類型,

// 通過反射機制我們該方法需要的類型ParameterInteger

// 但是前臺傳遞到後臺的是字元串”1”,而不是數字1,所以需要進行類型轉換。

String typeName = parameter.getType().getName();

System.out.println("DispatcherServlet ==== typeName"+typeName);

 

//註意:這裡一定要先將String 轉成 Object

Object parameterObj = parameterValue;

 

if(parameterObj != null) {

//註意:這裡如果需要完善, 還需要寫Float,Double等類型

if("java.lang.Integer".equals(typeName)) {

parameterObj = Integer.parseInt(parameterValue);

}

}

// 1.4 將獲取的參數值保存在Object類型的數組當中

//parameterValues[i] = parameterValue;

parameterValues[i] = parameterObj;

}

 

// 2. xxxController中的方法調用

// Object returnObj = method.invoke(xxxController, request, response);

Object returnObj = method.invoke(xxxController,parameterValues);

 

// 3, 視圖跳轉處理

if (returnObj != null) {

methodReturnStr = (String) returnObj;

if (methodReturnStr.startsWith("redirect:")) {

String redirectStr = methodReturnStr.substring("redirect:".length());

response.sendRedirect(request.getContextPath() + "/" + redirectStr);

return;

} else if (methodReturnStr.startsWith("forward:")) {

String forwardtStr = methodReturnStr.substring("forward:".length());

request.getRequestDispatcher(forwardtStr).forward(request, response);

return;

}

}

return;

}

}

throw new RuntimeException("ac值違法");

}

} catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {

e.printStackTrace();

}

}

}

 

 

6.2.5 回到XxxController中,如何給xxxService賦值??

 

我們將new EmpServiceImpl();刪除了,去掉了依賴,如何賦值?

而且service層也依賴dao,改成null,去掉了依賴,如何賦值?

 

 

 

 

 

 

6.2.6 如何解決?

applicationContext.xml文件中先描述我們需要哪些組件。然後再描述組件與組件之間的依賴關係。XxxController中需要XxxServiceXxxService中需要XxxDao

 

 

 

6.2.7 修改ClassPathXMLApplicationContext代碼, 查看獲取了xml中的哪些對象

package com.hy.io;

 

import java.io.IOException;

import java.io.InputStream;

import java.util.concurrent.ConcurrentHashMap;

 

import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import javax.xml.parsers.ParserConfigurationException;

 

import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.w3c.dom.Node;

import org.w3c.dom.NodeList;

import org.xml.sax.SAXException;

 

public class ClassPathXMLApplicationContext implements BeanFactory {

private ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();

 

// 在預設構造方法中載入配置文件

public ClassPathXMLApplicationContext() {

 

try {

InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("applicationContext.xml");

 

// 1,創建DocumentBuilderFactory工廠對象

DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();

 

// 2,創建DocumentBuilder對象

DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();

 

// 3,得到Document對象( 註意導入org.w3c.dom包中的)

Document document = documentBuilder.parse(inputStream);

 

// 4,獲得所有的Bean標簽

NodeList nodeList = document.getElementsByTagName("bean");

 

for (int i = 0, len = nodeList.getLength(); i < len; i++) {

Node node = nodeList.item(i);

System.out.println(node.getNodeType());// 1,1,1

 

if (node.getNodeType() == node.ELEMENT_NODE) {

Element element = (Element) node;

String id = element.getAttribute("id");

String className = element.getAttribute("class");

 

boolean flag = map.containsKey(id);

 

if (flag == true)

return;

 

Class clazz = Class.forName(className);

// 創建bean對象

Object o = clazz.newInstance();

// bean對象存儲到容器當中

map.put(id, o);

// 到目前為止,我們將所有的bean,已經實例化(new了一個對象),

// 並且存放到了容器當中,但是beanbean對象之間的依賴關係還沒有處理

}

}

System.out.println("=================");

// 5, 組裝bean之間的依賴關係,拿到bean對象之後,如果裡面有property標簽則進行組裝

for (int i = 0, len = nodeList.getLength(); i < len; i++) {

Node node = nodeList.item(i);

if (node.getNodeType() == Node.ELEMENT_NODE) {

Element element = (Element) node;

String id = element.getAttribute("id");

//

//element 就是獲取的bean對象,通過getChildNodes()方法

//來獲取這個對象有三個子節點,13是文本節點

 

NodeList childNodes = element.getChildNodes();

// System.out.println(childNodes.getLength());// 3,5,0

//

//if (i == 1) { //查看第二個bean標簽的5個子元素的類型分別是什麼,

// for (int j = 0; j < childNodes.getLength(); j++) {

// //NodeType3,8,3,1,3,

// //Node.TEXT_NODE    = 3;

// //Node.COMMENT_NODE = 8;

// //Node.ELEMENT_NODE = 1;

// System.out.print(childNodes.item(j).getNodeType()+",");

// }

//}

}

}

 

} catch (ParserConfigurationException e) {

e.printStackTrace();

} catch (SAXException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

} catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (InstantiationException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

}

}

 

@Override

public Object getBean(String id) {

return map.get(id);

}

 

public static void main(String[] args) {

ClassPathXMLApplicationContext applicationContext = new ClassPathXMLApplicationContext();

}

}

 

 

6.3 正式組裝bean之間的依賴關係

package com.hy.io;

 

import java.io.IOException;

import java.io.InputStream;

import java.lang.reflect.Field;

import java.util.concurrent.ConcurrentHashMap;

 

import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import javax.xml.parsers.ParserConfigurationException;

 

import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.w3c.dom.Node;

import org.w3c.dom.NodeList;

import org.xml.sax.SAXException;

 

public class ClassPathXMLApplicationContext implements BeanFactory {

private ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();

 

// 在預設構造方法中載入配置文件

public ClassPathXMLApplicationContext() {

 

try {

InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("applicationContext.xml");

 

// 1,創建DocumentBuilderFactory工廠對象

DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();

 

// 2,創建DocumentBuilder對象

DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();

 

// 3,得到Document對象( 註意導入org.w3c.dom包中的)

Document document = documentBuilder.parse(inputStream);

 

// 4,獲得所有的Bean標簽

NodeList nodeList = document.getElementsByTagName("bean");

 

for (int i = 0, len = nodeList.getLength(); i < len; i++) {

Node node = nodeList.item(i);

 

System.out.println(node.getNodeType());// 1,1,1

 

if (node.getNodeType() == node.ELEMENT_NODE) {

Element element = (Element) node;

String id = element.getAttribute("id");

String className = element.getAttribute("class");

 

boolean flag = map.containsKey(id);

 

if (flag == true)

return;

 

Class clazz = Class.forName(className);

// 創建bean對象

Object o = clazz.newInstance();

// bean對象存儲到容器當中

map.put(id, o);

// 到目前為止,我們將所有的bean,已經實例化(new了一個對象),

// 並且存放到了容器當中,但是beanbean對象之間的依賴關係還沒有處理

}

}

System.out.println("=================");

// 5, 組裝bean之間的依賴關係,拿到bean對象之後,如果裡面有property標簽則進行組裝

for (int i = 0, len = nodeList.getLength(); i < len; i++) {

Node node = nodeList.item(i);

if (node.getNodeType() == Node.ELEMENT_NODE) {

Element element = (Element) node;

String id = element.getAttribute("id");

//

// element 就是獲取的bean對象,通過getChildNodes()方法

// 來獲取這個對象有三個子節點,13是文本節點

 

NodeList childNodes = element.getChildNodes();

// System.out.println(childNodes.getLength());// 3,5,0

//

// if (i == 1) { //查看第二個bean標簽的5個子元素的類型分別是什麼,

// for (int j = 0; j < childNodes.getLength(); j++) {

// //NodeType3,8,3,1,3,

// //Node.TEXT_NODE = 3;

// //Node.COMMENT_NODE = 8;

// //Node.ELEMENT_NODE = 1;

// System.out.print(childNodes.item(j).getNodeType()+",");

// }

// }

 

for (int j = 0; j < childNodes.getLength(); j++) {

Node childNode = childNodes.item(j);

 

if (childNode.getNodeType() == Node.ELEMENT_NODE

&& "property".equals(childNode.getNodeName())) {

Element propertyElement = (Element)childNode;

 

//獲取其name屬性和ref屬性

String propertyName = propertyElement.getAttribute("name");

String propertyRef = propertyElement.getAttribute("ref");

 

//找到ref對應的實例對象

Object refObj = map.get(propertyRef);

 

//refObj設置到當前bean對應的對象的property屬性上來

Object beanObj = map.get(id);

 

//獲取該對象的類對象

Class beanClazz = beanObj.getClass();

 

//獲得該類對象的屬性

Field propertyField = beanClazz.getDeclaredField(propertyName);

 

//設置其可訪問性

propertyField.setAccessible(true);

 

propertyField.set(beanObj, refObj);

}

}

}

}

 

} catch (ParserConfigurationException e) {

e.printStackTrace();

} catch (SAXException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

} catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (InstantiationException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (NoSuchFieldException e) {

e.printStackTrace();

} catch (SecurityException e) {

e.printStackTrace();

}

}

 

@Override

public Object getBean(String id) {

return map.get(id);

}

 

public static void main(String[] args) {

ClassPathXMLApplicationContext applicationContext = new ClassPathXMLApplicationContext();

}

}

http://127.0.0.1:8080/mymvc4/emp.do?ac=add&ename=aaa&pwd=bbb

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在B/S系統開發中,前後端分離開發設計已成為一種標準,而VUE作為前端三大主流框架之一,越來越受到大家的青睞,Antdv是Antd在Vue中的實現。本系列文章主要通過Antdv和Asp.net WebApi開發學生信息管理系統,簡述前後端分離開發的主要相關內容,僅供學習分享使用,如有不足之處,還請指... ...
  • 大概是在18年的時候,當時還沒有疫情。當時工作中同時負責多個項目,有 PC 端運營管理後臺的,有移動端 M 站的,有微信小程式的,每天 git 分支切到頭昏眼花,每個需求提測需要發送郵件,而且周五要寫煩人的周報,我就萌生了做一個任務管理系統的想法。其實不管是日常需求還是處理線上 bug,都可以看作一 ...
  • 使用ref訪問子組件實例或子元素 點擊打開視頻講解更加詳細 儘管存在 prop 和事件,有的時候你仍可能需要在 JavaScript 里直接訪問一個子組件。為了達到這個目的,你可以通過 ref 這個 attribute 為子組件賦予一個 ID 引用。 <template> <div id="app" ...
  • SOLID 原則是面向對象編程和麵向對象設計的五個基本原則。當這些原則被一起應用時,它們使得一個程式員開發一個容易進行軟體維護和擴展的系統變得更加可能。 ...
  • 消息隊列中間件是分散式系統中重要的組件,主要解決應用耦合,非同步消息,削峰填谷等問題。實現高性能、高可用、可伸縮和最終一致性架構。 ...
  • 7.1 IOC (inversion of control) – 反轉控制 1) 之前我們在學JSP的時候,在CoreServlet中,我們創建xxxDao對象是如何創建的? IXxxDao xxxDao = new XxxDaoImpl( ) ; 這種寫法new了一個XxxDaoImpl類,這樣使 ...
  • 10. 什麼是ThreadLocal ThreadLocal翻譯成中文比較準確的叫法應該是:線程局部變數。或稱為 線程本地變數 這個玩意有什麼用處?先解釋一下,在併發編程的時候,一個單例模式的類的屬性,如果不做任何處理(是否加鎖,或者用原子類)其實是線程不安全的,各個線程都在操作同一個屬性,比如Co ...
  • 8. 過濾器 8.1 編寫字元過濾器 CharacterEncodingFilter 複製項目mymvc4,新建項目mymvc5 package com.hy.filter; import java.io.IOException; import javax.servlet.Filter; impor ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...