本項目目標是開發一個社區網站,擁有發帖、討論、搜索、登陸等一個正常社區擁有的功能。涉及到的版本參數爲:html
- JDK1.8
- Maven3.8.1(直接集成到IDEA)
- Springboot 2.5.1
- tomcat
參考網站(在使用框架過程當中可能會看的開發文檔):前端
https://mvnrepository.com/ 查找maven依賴java
https://mybatis.org/mybatis-3/zh/index.html mybatis的官方文檔,配置等都有說明mysql
項目代碼已發佈到github https://github.com/GaoYuan-1/web-projectgit
關於數據庫文件,該篇博客中已有提到,可去文中github獲取數據 MySQL基礎篇(一)github
本文第一篇只介紹了基礎,在(二)中將會介紹如何實現登陸界面等後續內容。最終將會把完整項目經歷發佈出來。web
本系列主要介紹的是實戰內容,對於理論知識介紹較少,適合有必定基礎的人。spring
首先建立一個項目,可利用Spring Initializrsql
本人配置以下:數據庫
maven項目的
pom.xml
中初始依賴以下,後面會增長更多依賴。
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
記錄一些基本概念,Spring的知識可能說的比較少,本篇關注於如何對網站進行實現。
Spring Bean是被實例的,組裝的及被Spring 容器管理的Java對象。
Spring 容器會自動完成@bean對象的實例化。
建立應用對象之間的協做關係的行爲稱爲:裝配(wiring),這就是依賴注入的本質。
在使用 Spring Initializr
以後,第一個接觸的註解爲:
@SpringBootApplication
咱們能夠把 @SpringBootApplication
看做是 @Configuration
、@EnableAutoConfiguration
、@ComponentScan
註解的集合。
根據 SpringBoot
官網,這三個註解的做用分別是:
@EnableAutoConfiguration
:啓用 SpringBoot 的自動配置機制@ComponentScan
: 掃描被@Component (@Service,@Controller)註解的 bean,註解默認會掃描該類所在的包下全部的類。@Configuration
:容許在 Spring 上下文中註冊額外的 bean 或導入其餘配置類(表示該類是配置類)Spring經過識別一些註解可讓容器自動裝填bean:
關於@Scope,負責聲明Bean的做用域:
@Scope("singleton") //惟一 bean 實例,Spring 中的 bean 默認都是單例的。 @Scope("prototype") //每次請求都會建立一個新的 bean 實例。 @Scope("request") //每一次 HTTP 請求都會產生一個新的 bean,該 bean 僅在當前 HTTP request 內有效。 @Scope("session") //每一次 HTTP 請求都會產生一個新的 bean,該 bean 僅在當前 HTTP session 內有效。
關於@Autowired:
自動導入對象到類中,被注入進的類一樣要被 Spring 容器管理。從構造器,到方法,到參數、屬性、註解,均可以加上@Autowired註解。
能夠先了解一些HTTP流的相關知識:(參考自MDN Web Docs)
當客戶端想要和服務端進行信息交互時(服務端是指最終服務器,或者是一箇中間代理),過程表現爲下面幾步:
打開一個TCP鏈接:TCP鏈接被用來發送一條或多條請求,以及接受響應消息。客戶端可能打開一條新的鏈接,或重用一個已經存在的鏈接,或者也可能開幾個新的TCP鏈接連向服務端。
發送一個HTTP報文:HTTP報文(在HTTP/2以前)是語義可讀的。在HTTP/2中,這些簡單的消息被封裝在了幀中,這使得報文不能被直接讀取,可是原理還是相同的。
GET / HTTP/1.1 Host: developer.mozilla.org Accept-Language: fr
讀取服務端返回的報文信息:
HTTP/1.1 200 OK Date: Sat, 09 Oct 2010 14:28:02 GMT Server: Apache Last-Modified: Tue, 01 Dec 2009 20:18:22 GMT ETag: "51142bc1-7449-479b075b2891b" Accept-Ranges: bytes Content-Length: 29769 Content-Type: text/html <!DOCTYPE html... (here comes the 29769 bytes of the requested web page)
關閉鏈接或者爲後續請求重用鏈接。
當HTTP流水線啓動時,後續請求均可以不用等待第一個請求的成功響應就被髮送。然而HTTP流水線已被證實很難在現有的網絡中實現,由於現有網絡中有不少老舊的軟件與現代版本的軟件共存。所以,HTTP流水線已被在有多請求下表現得更穩健的HTTP/2的幀所取代。
HTTP請求的例子:
響應的例子:
三層架構:表現層,業務層和數據訪問層。
MVC:Model(模型層),View(視圖層),Controller(控制層)
核心組件: DispatcherServlet
若是想給瀏覽器返回一個動態網頁,則須要一個工具支持,例如:Thymeleaf(模板引擎,生成動態的HTML)。
該引擎須要學習的有:標準表達式,判斷與循環,模板的佈局。
學習建議參考官方文檔 https://www.thymeleaf.org/index.html
@RequestMapping支持Servlet的request和response做爲參數,如下爲一個簡單示例:
@Controller @RequestMapping("/alpha") public class AlphaController { @RequestMapping("/hello") @ResponseBody public String sayHello(){ return "Hello Spring Boot."; } @RequestMapping("/http") public void http(HttpServletRequest request, HttpServletResponse response) throws IOException { //獲取請求數據 System.out.println(request.getMethod()); System.out.println(request.getServletPath());//請求路徑 Enumeration<String> enumeration = request.getHeaderNames();//獲得請求行的key while(enumeration.hasMoreElements()) { String name = enumeration.nextElement(); //當前值(key) String value = request.getHeader(name);//獲得value System.out.println(name + ":" + value); } System.out.println(request.getParameter("code")); // 返回響應數據 response.setContentType("text/html;charset=utf-8");//返回網頁類型的文本 PrintWriter writer = response.getWriter(); writer.write("<h1>牛客網</h1>");//這裏只進行簡單輸出 writer.close(); } }
在項目Controller層加入代碼,以response體返回一個html的文本。
這是經過底層對象處理請求的方式,便於理解。
更簡單的方式爲:
// GET請求,用於獲取某些數據 // /students?current=1&limit=20 假設查詢學生數據,第一頁,每頁20條 @RequestMapping(path = "/students", method = RequestMethod.GET) @ResponseBody // public String getStudents(int current,int limit) { //直接使用Int類型,前端控制器會自動識別匹配 // System.out.println(current); // System.out.println(limit); // return "some students"; // } // 也可加上註解 public String getStudents( @RequestParam(name = "current", required = false, defaultValue = "1") int current, @RequestParam(name = "limit", required = false, defaultValue = "1") int limit) { System.out.println(current); System.out.println(limit); return "some students"; }
利用@ResponseBody註解,實現效果爲:
控制檯返回結果:
利用這種方式,不管是返回數據仍是獲取數據都很方便。
另外,經過路徑方式傳參查詢的話:(注意,路徑長度並非無限的,並不能夠傳不少參數)
// /student/123 查詢某個學生,直接放在路徑中 @RequestMapping(path = "/student/{id}", method = RequestMethod.GET) @ResponseBody public String getStudent(@PathVariable("id") int id) { System.out.println(id); return "a student"; }
注意以上傳參時使用的兩個註解。
如何向瀏覽器提交數據?
在項目靜態文件中添加html文件,action指示路徑
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>增長學生</title> </head> <body> <form method="post" action="/community/alpha/student"> <p> 姓名:<input type="text" name="name"> </p> <p> 年齡:<input type="text" name="age"> </p> <p> <input type="submit" value="保存"> </p> </form> </body> </html>
//POST請求 @RequestMapping(path = "/student", method = RequestMethod.POST) @ResponseBody public String saveStudent(String name, int age) { System.out.println(name); System.out.println(age); return "success"; }
在Controller中代碼以下,展現效果:
控制檯:
從程序內部響應到HTML
//響應HTML數據 @RequestMapping(path = "/teacher", method = RequestMethod.GET) public ModelAndView getTeacher() { //這個對象就是向前端控制器返回的moder和view ModelAndView mav = new ModelAndView(); mav.addObject("name", "張三"); mav.addObject("age", 30); mav.setViewName("/demo/view");//這個view實際上指的是view.html return mav; }
Controller代碼
此外,還須要一個動態網頁,利用thymeleaf模板引擎(resource/templates)。
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <!--聲明這不是html文件,而是一個thymeleaf模板--> <head> <meta charset="UTF-8"> <title>Teacher</title> </head> <body> <p th:text="${name}"></p> <p th:text="${age}"></p> </body> </html>
實現效果,程序已經設定初始值。
模板引擎會自動進行處理。
另外一種方式:
@RequestMapping(path = "/school", method = RequestMethod.GET) public String getSchool(Model model) { //前端控制器會建立一個model model.addAttribute("name","大學"); model.addAttribute("age",80); return "/demo/view"; //這裏return的是view的路徑 }
這兩種方式是model和view的對象使用方式不一樣。效果仍是一致的,第二種要更加簡便一些。
異步請求能夠理解爲:當前網頁不刷新,可是進行了數據交互,好比註冊帳號時,常常會檢測用戶名是否重複,這時候網頁並無刷新,可是訪問了數據庫進行查詢。
//響應JSON數據(異步請求) // Java對象傳給瀏覽器:須要轉爲JS對象,這時候就能夠經過JSON進行轉化 // Java對象-> JSON字符串 -> JS對象等等 @RequestMapping(path = "/emp", method = RequestMethod.GET) @ResponseBody public Map<String,Object> getEmp() { //自動會將map轉爲JSON字符串 Map<String,Object> emp = new HashMap<>(); emp.put("name","張三"); emp.put("age",23); emp.put("salary",8000.00); return emp; }
注意,這裏並無返回html。
這裏只是簡單介紹了響應方式,之後的博客中會介紹具體應用及代碼。
MyBatis 是一款優秀的持久層框架,它支持自定義 SQL、存儲過程以及高級映射。MyBatis 免除了幾乎全部的 JDBC 代碼以及設置參數和獲取結果集的工做。MyBatis 能夠經過簡單的 XML 或註解來配置和映射原始類型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 對象)爲數據庫中的記錄。
在maven項目pom.xml中添加依賴
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.25</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency>
在SpringBoot框架下,只須要對application.properties進行配置,增長以下:
# DataSourceProperties spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/community?characterEncoding=utf-8&useSSL=false&serverTimezone=Hongkong spring.datasource.username=root spring.datasource.password=Ss6215615 #設置鏈接池,這個比較好 spring.datasource.type=com.zaxxer.hikari.HikariDataSource spring.datasource.hikari.maximum-pool-size=15 spring.datasource.hikari.minimum-idle=5 spring.datasource.hikari.idle-timeout=30000 # MybatisProperties mybatis.mapper-locations=classpath:mapper/*.xml mybatis.type-aliases-package=com.nowcoder.community.entity mybatis.configuration.useGeneratedKeys=true #自動匹配 a_b == aB mybatis.configuration.mapUnderscoreToCamelCase=true # logger,設置日誌,方便在控制檯查看信息 logging.level.com.nowcoder.community=debug
mybatis.type-aliases-package=com.nowcoder.community.entity
這行代碼聲明瞭SQL中記錄在Java中的對象位置,根據SQL中的屬性創建對象。
public class User { private int id; private String username; private String password; private String salt; private String email; private int type; private int status; private String activationCode; private String headerUrl; private Date createTime; //等等,還有set,get,toString
創建對象以後,在項目中的dao文件,創建UserMapper(對於User的操做)接口,Mybatis只須要經過xml文件對操做進行聲明。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.nowcoder.community.dao.UserMapper"> <!-- 這裏寫UserMapper的全限定名 --> <sql id="selectFields"> id, username, password, salt, email, type, status, activation_code, header_url, create_time </sql> <sql id="insertFields"> username, password, salt, email, type, status, activation_code, header_url, create_time </sql> <select id="selectById" resultType="User"> <!-- 配置裏進行過設置package,不然須要寫全限定名 --> select <include refid="selectFields"></include> from user where id = #{id} <!-- 這裏的意思是要引用方法的參數 --> </select> <select id="selectByName" resultType="User"> <!-- 配置裏進行過設置package,不然須要寫全限定名 --> select <include refid="selectFields"></include> from user where username = #{username} <!-- 這裏的意思是要引用方法的參數 --> </select> <select id="selectByEmail" resultType="User"> <!-- 配置裏進行過設置package,不然須要寫全限定名 --> select id, username, password, salt, email, type, status, activation_code, header_url, create_time from user where email = #{email} <!-- 這裏的意思是要引用方法的參數 --> </select> <insert id="insertUser" parameterType="User" keyProperty="id"> insert into user (<include refid="insertFields"></include>) values(#{username}, #{password}, #{salt}, #{email}, #{type}, #{status}, #{activationCode}, #{headerUrl}, #{createTime}) </insert> <update id="updateStatus"> update user set status = #{status} where id = #{id} </update> <update id="updateHeader"> update user set header_url = #{headerUrl} where id = #{id} </update> <update id="updatePassword"> update user set password = #{password} where id = #{id} </update> </mapper>
這裏創建了增刪改的操做。
mybatis.mapper-locations=classpath:mapper/*.xml
根據已有的配置在resource文件夾中創建mapper目錄和.xml文件。
因爲.xml文件不會自動檢測編譯,建議在test中依次測試相應功能,以避免出現錯誤。
本項目計劃使用SpringBoot框架進行一個社交網站的開發,首先使用Spring Initializr對maven項目進行創建,以後對Spring的基本概念進行了必定闡述,IOC和AOP均沒有講到,將會在後續開放的Spring學習篇中,對SpringMVC的基本使用(GET,POST請求和響應數據)進行了代碼示範,方便理解後續代碼。另外,介紹了Mybatis的使用,以及公佈了部分示範代碼。
上手起來是很是快的,本系列的目的在於,重點講解實戰部分,理論部分將在其餘博客中展開。
下篇博客將會對網站的登錄界面等如何實現進行闡述。