天天看點

《Spring 實戰》第四版第五章javaConfig實作Maven項目

最近在學習Spring實戰第五章:利用JavaConfig代替xml檔案實作Spring mvc配置,弄了好久終于用Maven實作完成了,現在将代碼分享出去。

需要注意的是:隻有在tomcat3.0中才支援java配置的DispatcherServlet環境,如果低于這個版本,隻能使用web.xml配置

前期的Maven項目建立可以看這位部落客寫的,雖然比較麻煩但确實有效。

https://www.cnblogs.com/noteless/p/5213075.html

java代碼目錄:

《Spring 實戰》第四版第五章javaConfig實作Maven項目

webapp目錄:

在這裡我沒有将jsp檔案放在書中所設定的view檔案夾,而是直接放在最外層,實作時可以自己選擇,到時候改一下WebConfig裡視圖解析器的配置就好。

《Spring 實戰》第四版第五章javaConfig實作Maven項目

我會按照書中的大緻順序貼上代碼,我的項目名稱為webapp052,書中項目名稱是spittr

一、pom檔案

<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/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>jiajia</groupId>
	<artifactId>webapp052</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>webapp052 Maven Webapp</name>
	<url>http://maven.apache.org</url>
	<dependencies>
			<dependency>
			  <groupId>org.hibernate.validator</groupId>
			  <artifactId>hibernate-validator</artifactId>
			  <version>6.0.16.Final</version>
			</dependency>
			<dependency>
				<groupId>org.apache.commons</groupId>
				<artifactId>commons-lang3</artifactId>
				<version>3.5</version>
			</dependency>
			 <!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
			 <dependency>
			   <groupId>javax.validation</groupId>
			   <artifactId>validation-api</artifactId>
			   <version>2.0.1.Final</version>
			</dependency>
			<dependency>
				<groupId>org.hamcrest</groupId>
				<artifactId>hamcrest-core</artifactId>
				<version>1.3</version>
			</dependency> 
			<dependency>
			    <groupId>org.hamcrest</groupId>
			    <artifactId>hamcrest-library</artifactId>
			    <version>1.3</version>
			</dependency>
			<dependency>
				<groupId>org.mockito</groupId>
				<artifactId>mockito-all</artifactId>
				<version>1.9.5</version>
			</dependency>
			<dependency>
				<groupId>org.aspectj</groupId>
				<artifactId>aspectjweaver</artifactId>
				<version>1.8.9</version>
			</dependency>
			<dependency>
				<groupId>org.aspectj</groupId>
				<artifactId>aspectjtools</artifactId>
				<version>1.8.9</version>
			</dependency>
			<dependency>
				<groupId>org.aspectj</groupId>
				<artifactId>aspectjrt</artifactId>
				<version>1.8.9</version>
			</dependency>
			<dependency>
				<groupId>aopalliance</groupId>
				<artifactId>aopalliance</artifactId>
				<version>1.0</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-expression</artifactId>
				<version>5.1.3.RELEASE</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-aspects</artifactId>
				<version>5.1.3.RELEASE</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-aop</artifactId>
				<version>5.1.3.RELEASE</version>
			</dependency>
			<dependency>
				<groupId>junit</groupId>
				<artifactId>junit</artifactId>
				<version>4.12</version>
				<scope>test</scope>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-context</artifactId>
				<version>5.1.3.RELEASE</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-webmvc</artifactId>
				<version>5.1.3.RELEASE</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-web</artifactId>
				<version>5.1.3.RELEASE</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-beans</artifactId>
				<version>5.1.3.RELEASE</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-core</artifactId>
				<version>5.1.3.RELEASE</version>
			</dependency>
			<!--spring單元測試依賴 -->
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-test</artifactId>
				<version>5.1.3.RELEASE</version>
				<scope>test</scope>
			</dependency>
			<!--spring-test4.12的版本是需要有一個依賴包的。 -->
			<dependency>
				<groupId>org.hamcrest</groupId>
				<artifactId>hamcrest-core</artifactId>
				<version>1.3</version>
				<scope>test</scope>
			</dependency>
			<dependency>
				<groupId>com.github.stefanbirkner</groupId>
				<artifactId>system-rules</artifactId>
				<version>1.9.0</version>
			</dependency>
			<dependency>
				<groupId>javax.servlet</groupId>
				<artifactId>javax.servlet-api</artifactId>
				<version>3.1.0</version>
			</dependency>
			<dependency>
				<groupId>commons-lang</groupId>
				<artifactId>commons-lang</artifactId>
				<version>2.1</version>
			</dependency>
		</dependencies>
		<build>
			<finalName>webapp052</finalName>
		</build>
</project>

           

二、Spring mvc基本配置

總共有三個檔案,在spittr.config檔案夾下。

WebConfig配置

package spittr.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

import spittr.data.SpitterRepository;
import spittr.data.SpitterRepositoryimpl;
import spittr.data.SpittleRepository;
import spittr.data.SpittleRepositoryimpl;
//隻有在tomcat3.0中才支援java配置的DispatcherServlet環境,如果低于這個版本,隻能使用web.xml配置
@Configuration
@EnableWebMvc            //啟動mvc
@ComponentScan("spittr.web") //掃描這個包裡的的元件
//原書為實作WebMvcConfigurerAdapter接口,但是此接口已經廢棄,是以用WebMvcConfigure代替
public class WebConfig implements WebMvcConfigurer{
	
	//配置jsp視圖解析器
	@Bean
	public ViewResolver viewResolver() {
		System.out.println("視圖解析啟動");
		InternalResourceViewResolver resolver=new InternalResourceViewResolver();
		resolver.setPrefix("/WEB-INF/");
		resolver.setSuffix(".jsp");
		//設定是否将所有spring上下文中的bean都作為請求屬性通路
		resolver.setExposeContextBeansAsAttributes(true);
		return resolver;
	}
	
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
		//通過這個方法要求将靜态資源轉發到servlet容器,而不是用DispatcherServlet
			configurer.enable();
	}
	
	//隻想要實作home視圖的可以先不寫這兩個bean
	@Bean
	public SpittleRepository spittleRepository() {
		return new SpittleRepositoryimpl();
	}
	@Bean
	public SpitterRepository spitterRepository() {
		return new SpitterRepositoryimpl();
	}
	
}

           

RootConfig配置

package spittr.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import org.springframework.context.annotation.ComponentScan.Filter;

@Configuration
@ComponentScan(basePackages = { "spittr.data" }, excludeFilters = {
		@Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class),
		//不掃描web包,否則會在建立bean時報錯
		@Filter(type=FilterType.REGEX,pattern="spittr.web")})
public class RootConfig {
}

           

需要注意的是項目啟動是先加載 RootConfig,随後才會加載WebConfig,是以為了防止RootConfig掃描到web裡的bean進而出現報錯,設定過濾防止 RootConfig掃描web裡的bean,也就是說在WebConfig建立Controller類的bean時, RootConfig已經預先找到了data檔案裡的Repository類的bean,進而可以成功注入。

SpittrWebAppInitializer配置類

package spittr.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class SpittrWebAppInitializer extends  AbstractAnnotationConfigDispatcherServletInitializer{
	
	@Override
	protected Class<?>[] getRootConfigClasses() {
		// TODO Auto-generated method stub
		return new Class<?>[] {RootConfig.class};
	}

	@Override
	protected Class<?>[] getServletConfigClasses() {
		// TODO Auto-generated method stub
		return new Class<?>[] {WebConfig.class};
	}

	@Override
	protected String[] getServletMappings() {
		// TODO Auto-generated method stub
		return new String[] { "/" };
	}

}

           

二、基本的home視圖實作

在spittr.web檔案夾下建立一個HomeController類,作為控制器

package spittr.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping({"/","/homepage"})   //定義類級别的請求處理,控制器映射到“/”
public class HomeController {
	
	@RequestMapping(method=RequestMethod.GET)
	public String home() {
		return "home";
	}
}

           

home.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Spittr</title>
</head>
<body>
	<h1>Welcome to Spittr homepage!</h1>
	<a href=" <c:url value='/spittles'/> " target="_blank" rel="external nofollow"  >Spittles</a>
	<a href=" <c:url value='/spitter/register'/>" target="_blank" rel="external nofollow"  > Register</a>
</body>
</html>
           

注意添加jstl和standard兩個檔案。

右鍵項目Run on Server運作

《Spring 實戰》第四版第五章javaConfig實作Maven項目

得到結果,注意這裡我的端口号是8888,請使用自己的tomcat的端口号,一般預設為8080

《Spring 實戰》第四版第五章javaConfig實作Maven項目

三、傳遞資料模型到視圖中

現在讓我們完成spittle部分,首先建立一個spittr對象

package spittr;

import java.util.Date;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

public class Spittle {
	private final Long id;
	private final String message;
	private final Date time;
	private Double latitude;
	private Double longitude;
	
	//在這些構造方法裡我添加了一個id的屬性,原書是沒有的
	public Spittle(Long id,String message,Date time) {
		this(id,message,time,null,null);
	}
	public Spittle(Long id,String message,Date time,Double latitude,Double longitude) {
		this.id=id;
		this.message=message;
		this.time=time;
		this.latitude=latitude;
		this.longitude=longitude;
	}
	public Long getId() {
		return id;
	}
	public String getMessage() {
		return message;
	}
	public Date getTime() {
		return time;
	}
	public Double getLatitude() {
		return latitude;
	}
	public Double getLongitude() {
		return longitude;
	}
	
	@Override
	  public boolean equals(Object that) {
	    return EqualsBuilder.reflectionEquals(this, that, "id", "time");
	  }
	 @Override
	 public int hashCode() {
	   return HashCodeBuilder.reflectionHashCode(this, "id", "time");
	 }
}

           

然後定義一個存儲使用者發表日志的接口SpittleRepository

package spittr.data;
import java.util.List;
import spittr.Spittle;

public interface SpittleRepository {
	//傳回給定的Spittle清單
	List<Spittle> findSpittles(long max ,int count);
	//找到單個Spittle并傳回
	Spittle findone(long spittleID);
}
           

接下來是其接口實作,書中沒有給出具體的實作類,這是我自己寫的,如果隻是如書中所說進行測試,可以不實作此接口。

package spittr.data;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.stereotype.Component;
import spittr.Spittle;

public class SpittleRepositoryimpl implements SpittleRepository{
	private List<Spittle> spittleList=new ArrayList<Spittle>();
	
	//裝填spittle
	public SpittleRepositoryimpl( ) {
		// TODO Auto-generated constructor stub
		for(long i=0;i<20;i++) {
			spittleList.add(new Spittle(i,"今天很高興"+i, new Date()));
		}
	}
	@Override
	public List<Spittle> findSpittles(long max, int count) {
		// TODO Auto-generated method stub
		return spittleList;
	}
	@Override
	public Spittle findone(long spittleID) {
		// TODO Auto-generated method stub
		return new Spittle(spittleID, "指定的Spitttle"+spittleID, new Date());
	}
	
}
           

現在我們建立SpittleController,以實作具體的視圖通路。

package spittr.web;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import spittr.data.SpittleRepository;

@Controller
@RequestMapping("/spittles") //解析帶有該符号的url
public class SpittleController {
	private SpittleRepository spittleRepository;
	
	@Autowired
	public SpittleController(SpittleRepository spittleRepository) {
		this.spittleRepository=spittleRepository;
	}
	
	//請求目前最新20個spittle
	@RequestMapping(method=RequestMethod.GET)
	public String spittles(Model model) {
		System.out.println("------------------------s");
	//求最新的20個spittle,實際上這個參數在我的具體實作類裡毫無作用,因為我沒有使用這個參數
		model.addAttribute(spittleRepository.findSpittles(Long.MAX_VALUE, 20)); 
		return "spittles";//請求jsp視圖
	}
	
	//請求特定的單個spittle,這裡采用書中的通過路徑參數接受輸入的辦法
	@RequestMapping(value="/{spittleId}" ,method=RequestMethod.GET)
	public String spittlesone(Model model,@PathVariable long spittleId) {
		System.out.println("------------------------spittlesone");
		model.addAttribute(spittleRepository.findone(spittleId)); 
		return "spittle";//請求jsp視圖
	}
}
           

下面是spittles和spittle的兩個jsp視圖

spittles.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
Hello!<br/>
<!-- 因為不可以直接通路WEB-INF下的檔案,是以設定了一個超連結  -->
<a href=" <c:url value='/spittles/12345'/> " target="_blank" rel="external nofollow"  >擷取一個指定的Spittle</a>
<c:forEach items="${spittleList}" var="spittle">
	<li id="spittle_<c:out value='spittle.id'/>">
		<div class="spittleMessage">
			<c:out value="${spittle.message }"/>
		</div>
		<div>
			<span class="spittleTime"><c:out value="${spittle.time}"/></span>
			<span class="spittleLocation">
				(<c:out value="${spittle.latitude}"/>,<c:out value="${spittle.longitude }"></c:out>)
			</span>
		</div>
	</li>
</c:forEach>
<div class="spittleView">
	<div class="spittleMessage"><c:out value="${spittle.message}"/></div>
	<div class="spittleTime"><c:out value="${spittle.time}"/></div>
</div>
</body>
</html>
           

spittle.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
spittle
<div class="spittleView">
	<div class="spittleMessage">
		<c:out value="${spittle.message}"></c:out>
	</div>
	<div>
		<span class="spittleTime"><c:out value="${spittle.time }"></c:out></span>
	</div>
</div>
</body>
</html>
           

啟動項目,通過home頁面的spittles連結通路得到如下頁面。

《Spring 實戰》第四版第五章javaConfig實作Maven項目

點選擷取一個指定的Spittle

《Spring 實戰》第四版第五章javaConfig實作Maven項目

四、表單的送出與校驗

在之前的home視圖中,擁有一個使用者注冊的連結,現在我們來實作使用者注冊的操作。

使用者在點選注冊之後,應提供一個表單視圖以供使用者填寫,在填寫完畢後,應檢查填寫是否規範,然後跳轉到注冊後的使用者界面。

我們先完成一個包含使用者基本資訊的Spitter類,通過在這個類上的屬性添加注解進行表單的校驗。

package spittr;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.hibernate.validator.constraints.Email;

public class Spitter {

  private Long id;
  
  @NotNull
  @Size(min=5, max=16)
  private String username;

  @NotNull
  @Size(min=5, max=25)
  private String password;
  
  @NotNull
  @Size(min=2, max=30)
  private String firstName;

  @NotNull
  @Size(min=2, max=30)
  private String lastName;
  
  //原書中有notnull注解,但是加上這個注解會在注冊頁面報錯,因為注冊頁面沒有添加關于此的資訊輸入
  @Email
  private String email;

  public Spitter() {}
  
  public Spitter(String username, String password, String firstName, String lastName, String email) {
    this(null, username, password, firstName, lastName, email);
  }

  public Spitter(Long id, String username, String password, String firstName, String lastName, String email) {
    this.id = id;
    this.username = username;
    this.password = password;
    this.firstName = firstName;
    this.lastName = lastName;
    this.email = 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 Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public String getFirstName() {
    return firstName;
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
  
  public String getEmail() {
    return email;
  }
  
  public void setEmail(String email) {
    this.email = email;
  }

  @Override
  public boolean equals(Object that) {
    return EqualsBuilder.reflectionEquals(this, that, "firstName", "lastName", "username", "password", "email");
  }
  
  @Override
  public int hashCode() {
    return HashCodeBuilder.reflectionHashCode(this, "firstName", "lastName", "username", "password", "email");
  }

}
           

然後再添加一個儲存所有使用者資訊的SpitterRepository及其實作。

package spittr.data;
import spittr.Spitter;

public interface SpitterRepository {

  Spitter save(Spitter spitter);
  Spitter findByUsername(String username);
}
           
package spittr.data;

import java.util.ArrayList;
import java.util.List;

import spittr.Spitter;

public class SpitterRepositoryimpl implements SpitterRepository {
	private List<Spitter> spitterList=new ArrayList<Spitter>();
	
	//存儲一個spitter并傳回此spitter
	@Override
	public Spitter save(Spitter spitter) {
		// TODO Auto-generated method stub
		spitterList.add(spitter);
		return spitter;
	}
	//通過username查找特定的使用者資訊
	@Override
	public Spitter findByUsername(String username) {
		// TODO Auto-generated method stub
		for(Spitter name:spitterList) {
			if(name.getUsername().equals(username)) {
				//找到則傳回對應的spitter
				return name;
			}
		}
		return spitterList.get(0);
	}

}
           

下面是處理表單送出和跳轉的SpitterController

package spittr.web;
import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import spittr.Spitter;
import spittr.data.SpitterRepository;

@Controller
@RequestMapping("/spitter") //解析帶有該符号的url
public class SpitterController {
	private SpitterRepository spitterRepository;
	
	@Autowired
	public SpitterController(SpitterRepository spittlerRepository) {
		// TODO Auto-generated constructor stub
		this.spitterRepository=spittlerRepository;
	}
	
	//處理使用者注冊請求
	@RequestMapping(value="/register" ,method=RequestMethod.GET)
	public String showRegistrationForm() {
		return "registerForm";
	}
	
	//處理使用者系統資料庫單的送出,注意方式為POST
	@RequestMapping(value="/register" ,method=RequestMethod.POST)
	public String processRegistration(@Valid Spitter spitter,Errors errors) {
		//如果不符合規則,則傳回注冊界面
		if(errors.hasErrors()) {
			System.out.println("error!!"+errors);
			return "registerForm";
		}
		//如果符合規則,則保持并重定向到使用者注冊後的界面
		System.out.println("-----------------符合注冊規則----------------");
		spitterRepository.save(spitter);
		return "redirect:/spitter/"+spitter.getUsername();
	}
	//轉到使用者注冊完成後的profile頁面
	@RequestMapping(value="/{username}" ,method=RequestMethod.GET)
	public String showSpitterProfile(@PathVariable String username,Model model) {
		Spitter spitter=spitterRepository.findByUsername(username);
		model.addAttribute("spitter",spitter);
		return "profile";
	}

}
           

下面是需要傳回的視圖registerForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Spitter Register</title>

</head>
<body>
	<h1>Spitter Register</h1>
	<form method="POST">
		First Name:<input type="text" name="firstName"/><br/>
		Last Name:<input type="text" name="lastName"/><br/>
		Username:<input type="text" name="username"/><br/>
		Password:<input type="password" name="password"/><br/>
		<input type="submit" value="Register"/><br/>
	</form>
</body>
</html>
           

以及下面的profile.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Your Profile</title>
</head>
<body>
	<h1>Your profile</h1>
	<c:out value="${spitter.username}"></c:out><br/>
	<c:out value="${spitter.firstName }"></c:out>
	<c:out value="${spitter.lastName }"></c:out>
</body>
</html>
           

項目啟動,通過home視圖,可以進入注冊界面,這張圖的位址出現了jsessionid之類的東西,手動删去不影響程式,貌似是第一次運作系統自動生成的東西。

《Spring 實戰》第四版第五章javaConfig實作Maven項目

點選注冊按鈕,系統會監測是否符合規則,若符合命名規則,則跳轉到使用者界面。

《Spring 實戰》第四版第五章javaConfig實作Maven項目

以上就是工程的全部内容,如果有任何意見歡迎各位高手指出。

如果需要項目資源,請到以下連結下載下傳:

https://download.csdn.net/download/weixin_43690318/11180532

繼續閱讀