1. 程式人生 > >Spring4.X + Spring MVC + Mybatis3 零配置應用開發框架搭建詳解 (3)

Spring4.X + Spring MVC + Mybatis3 零配置應用開發框架搭建詳解 (3)

Spring4.X + Spring MVC + Mybatis3 零配置應用開發框架搭建詳解(3) - 實現最基本的登入處理

1. 基本架構:

        基礎框架搭建完成後,我們開始進行Spring + SpringMVC + Mybatis的整合,來完成登入功能的處理。我們根據資料流向,來建立相應的內容,先看看大致的資料流向圖:


        根據上面的資料流向圖,需要建立使用者登入頁面、登入成功頁面,許可權管理模組、控制層、服務層、資料庫持久層,下面我們分別來建立對應的內容:

2. 建立使用者登入頁面和登入後的頁面

首先修改【webapp】下的【login.jsp】,新增一個需要輸入登入資訊的表單,然後在【WEB-INF】下建立【pages】目錄,在【pages】目錄下建立【index】目錄,在【index】目錄下建立【index.jsp】,不要問為什麼建立那麼多檔案目錄和層級,太麻煩,因為這是我的習慣,真正做專案後層級劃分的好處以後你就懂。

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title>登入</title>
</head>
<body>

<h1>系統登入</h1>

<div>
  <c:if test="${param.error != null}">
    <p>使用者名稱密碼錯誤!</p>
  </c:if>
  <c:if test="${param.logout != null}">
    <p>您已登出!</p>
  </c:if>
</div>
<c:url value="/login" var="loginUrl"/>
<form action="${loginUrl}" method="post" id="loginForm">
  <div>
    <input type="text" name="username" class="username" placeholder="使用者名稱" autocomplete="off"/>
  </div>
  <div>
    <input type="password" name="password" class="password" placeholder="密碼" oncontextmenu="return false" onpaste="return false"/>
  </div>
  <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
  <button id="submit" type="submit">登入</button>
</form>


</body>
</html>

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
    <title>首頁</title>
</head>

<body>
<h1>首頁</h1>

<h2>登入成功</h2>
</body>
</html>

3. 在pom.xml中新增依賴jar包

        首先在web專案下的pom.xml中新增公共的依賴庫,以保證配置重用。

        下面主要新增的是Spring核心的幾個公用依賴包和日誌包,以及工具類。外掛中主要配置指定編譯JDK的版本,以及資原始檔的配置。

提示:新增依賴包的時候要注意設定Maven源的事,如果你自己設定的源出現問題,可以看看我的這篇博文:Maven國內源設定 - OSChina國內源失效了,別更新了

【Web專案下的pom.xml】

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.aitongyi.web</groupId>
    <artifactId>web</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 將專案定義為公共專案 -->
    <packaging>pom</packaging>

    <modules>
        <module>back</module>
        <module>dao</module>
        <module>bean</module>
        <module>cache</module>
        <module>service</module>
        <module>task</module>
    </modules>

    <!-- 專案的依賴包 -->
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
            <version>2.2.2</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.1.3</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.3</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-access</artifactId>
            <version>1.1.3</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.6.6</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.6.6</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.3</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-dbcp2</artifactId>
            <version>2.1.1</version>
        </dependency>

        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.6</version>
        </dependency>

         
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- end -->
    </dependencies>


    <!-- repositories節點是配置maven下載jar的中央倉庫,
    預設的是國外的,下載奇慢無比,推薦使用自己搭建sonatype nexus中央倉庫 -->
    <repositories>
        <repository>
            <id>central</id>
            <name>Central Repository</name>
            <url>http://repo1.maven.org/maven2/</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>jboss-public-repository-group</id>
            <name>JBoss Public Repository Group</name>
            <url>http://repository.jboss.org/nexus/content/groups/public/</url>
            <layout>default</layout>
            <releases>
                <enabled>true</enabled>
                <updatePolicy>never</updatePolicy>
            </releases>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>never</updatePolicy>
            </snapshots>
        </repository>
        <repository>
            <id>jboss-deprecated</id>
            <name>JBoss Deprecated</name>
            <url>https://repository.jboss.org/nexus/content/repositories/deprecated/</url>
            <layout>default</layout>
            <releases>
                <enabled>true</enabled>
                <updatePolicy>never</updatePolicy>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>jboss-maven2-brew</id>
            <name>JBoss Maven 2 Brew Repository</name>
            <url>http://repository.jboss.org/maven2-brew/</url>
            <layout>default</layout>
            <releases>
                <enabled>true</enabled>
                <updatePolicy>never</updatePolicy>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>

        <repository>
            <id>io.spring.repo.maven.release</id>
            <url>http://repo.spring.io/release/</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>io.spring.repo.maven.milestone</id>
            <url>http://repo.spring.io/milestone/</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
   
    <build>
        <plugins>
            <!-- 指定Maven編譯外掛,如果不設定,它就會用maven-compiler-plugin預設的jdk版本來進行處理 -->
            <!-- 這樣就容易出現版本不匹配的問題,以至於可能導致編譯不通過的問題 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <fork>true</fork>
                    <verbose>true</verbose>
                    <encoding>UTF-8</encoding>
                    <compilerArguments>
                        <sourcepath>${project.basedir}/src/main/java</sourcepath>
                    </compilerArguments>
                </configuration>
            </plugin>
            <!--  maven-resources-plugin則用來處理資原始檔。預設的主資原始檔目錄是src/main/resources,
            很多使用者會需要新增額外的資原始檔目錄,這個時候就可以通過配置maven-resources-plugin來實現。
            此外,資原始檔過濾也是Maven的一大特性,你可以在資原始檔中使用${propertyName}形式的Maven屬性,
            然後配置maven-resources-plugin開啟對資原始檔的過濾,之後就可以針對不同環境通過命令列或者Profile傳入屬性的值,
            以實現更為靈活的構建。  -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>


然後我們再來配置【back】模組中pom.xml的內容:

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>web</artifactId>
        <groupId>com.aitongyi.web</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>back</artifactId>
    <packaging>war</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.aitongyi.web</groupId>
            <artifactId>dao</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>com.aitongyi.web</groupId>
            <artifactId>bean</artifactId>
            <version>${project.version}</version>
        </dependency>

        <!-- spring  -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>4.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>4.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
            <version>4.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
            <version>2.2.2</version>
        </dependency>
        <!-- end -->

        <!-- serlvet & jstl -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- end -->

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.6</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-dbcp2</artifactId>
            <version>2.1.1</version>
        </dependency>

    </dependencies>
</project>

4. 編寫零配置程式碼

4.1 【back】專案    

        在【back】專案的【src/main/java】目錄下建立【com.aitongyi.web.back.conf】配置程式碼包、【com.aitongyi.web.back.controller】控制層程式碼包;

在【dao】專案的【src/main/java】目錄下建立【com.aitongyi.web.dao.conf】配置程式碼包、【com.aitongyi.web.dao.mapper】持久層程式碼包;

在【service】專案的【src/main/java】目錄下建立【com.aitongyi.web.service】服務層程式碼包

在【bean】專案的【src/main/java】目錄下建立【com.aitongyi.web.bean】模型程式碼包

在【back】專案【com.aitongyi.web.back.conf】包中建立五個配置物件:

【BackConfig.java】:負責管理基本配置資訊

import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

@Configurable
@PropertySource(value={"classpath:back.properties"})
public class BackConfig {
	@Bean
    public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
        return new PropertySourcesPlaceholderConfigurer();
    }
	
	@Bean(name="schedulerFactoryBean")
	public SchedulerFactoryBean schedulerFactoryBean(){
		return new SchedulerFactoryBean();
	}

}

【MvcConfig.java】:負責處理SpirngMVC的配置資訊以及元件的載入

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@EnableWebMvc
@EnableAspectJAutoProxy
@EnableScheduling
@ComponentScan(basePackages = {"com.aitongyi.web.back.controller","com.aitongyi.web.service"})
@MapperScan("com.aitongyi.web.dao.mapper")
public class MvcConfig extends WebMvcConfigurerAdapter {
 
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

    }
 
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    /**
     * jsp檢視解析器
     * @return
     */
    @Bean
    public InternalResourceViewResolver jspViewResolver() {
        InternalResourceViewResolver bean = new InternalResourceViewResolver();
        bean.setViewClass(org.springframework.web.servlet.view.JstlView.class);
        bean.setPrefix("/WEB-INF/pages/");
        bean.setSuffix(".jsp");
        return bean;
    }

    /**
     *  公共部分解析器
     * @return
     */
    @Bean(name="multipartResolver")
	public CommonsMultipartResolver commonsMultipartResolver(){
		CommonsMultipartResolver common = new CommonsMultipartResolver();
		common.setMaxUploadSize(10 * 1024 * 1024);//10M
		return common;
	}
    
}

SecurityConfig.java】:負責安全相關的配置處理,其中有一段程式碼:

auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(md5Encoder);

這是SpringSecurity安全框架自動處理的邏輯,首先是通過username查詢users表中是否有記錄,然後通過將密碼進行MD5加密,去跟資料庫中的密碼比對,如果相同就讓使用者執行configure方法中配置的登陸策略。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.security.web.header.HeaderWriter;
import org.springframework.security.web.header.HeaderWriterFilter;
import org.springframework.web.filter.CharacterEncodingFilter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	private static Md5PasswordEncoder md5Encoder = new Md5PasswordEncoder();

	@Autowired
	private DataSource dataSource;

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(md5Encoder);
	}

	@Override
	public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers("/resource/**");
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {

		http
//				將login.jsp定為登陸頁面,只處理/login這個請求
				.formLogin().loginPage("/login.jsp").and().formLogin().loginProcessingUrl("/login")
//				如果登陸成功就跳轉到/home這個地址,如果失敗就跳轉到/?error=1
				.and().formLogin().defaultSuccessUrl("/home").and().formLogin().failureUrl("/?error=1");
//		這裡配置的是登出的請求
		http.logout().logoutUrl("/logout")
//				登陸成功後跳轉的地址,以及刪除的cookie名稱
				.and().logout().logoutSuccessUrl("/")
				.and().logout().deleteCookies("JSESSIONID");
//		配置記住我的過期時間
		http.rememberMe().tokenValiditySeconds(1209600)
				.and().rememberMe().rememberMeParameter("remember-me");
		CharacterEncodingFilter encodeFilter = new CharacterEncodingFilter();
		encodeFilter.setEncoding("utf-8");
		encodeFilter.setForceEncoding(true);
		http.addFilterBefore(encodeFilter, CsrfFilter.class); // 放在csrf filter前面
		http.headers().disable();
		HeaderWriter headerWriter = new HeaderWriter() {
			public void writeHeaders(HttpServletRequest request, HttpServletResponse response) {
				response.setHeader("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
				response.setHeader("Expires", "0");
				response.setHeader("Pragma", "no-cache");
				response.setHeader("X-Frame-Options", "SAMEORIGIN");
				response.setHeader("X-XSS-Protection", "1; mode=block");
				response.setHeader("x-content-type-options", "nosniff");
			}
		};
		List<HeaderWriter> headerWriterFilterList = new ArrayList<>();
		headerWriterFilterList.add(headerWriter);
		HeaderWriterFilter headerFilter = new HeaderWriterFilter(headerWriterFilterList);
		http.addFilter(headerFilter);
	}
}

WebApplicationInitializer.java】:這是整個專案的核心。Servlet3.0規範,支援將web.xml相關配置也硬編碼到程式碼中[servlet,filter,listener,等等],並由javax.servlet.ServletContainerInitializer的實現類負責在容器啟動時進行載入,

spring提供了一個實現類SpringServletContainerInitializer(在spring-web包中的org.springframework.web目錄),該類會呼叫所有org.springframework.web.WebApplicationInitializer實現類的onStartup方法,將相關的元件註冊到伺服器;而我們的WebApplicationInitializer繼承自AbstractAnnotationConfigDispatcherServletInitializer,而AbstractAnnotationConfigDispatcherServletInitializer就實現了org.springframework.web.WebApplicationInitializer的onStartup方法,所以WebApplicationInitializer就是整個專案的關鍵,我們的整個專案就是通過它來啟動。

import com.aitongyi.web.dao.conf.DatabaseConfig;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import javax.servlet.Filter;

public class WebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
	/**
	 * 獲取配置資訊
	 * @return
	 */
	@Override
	protected Class<?>[] getRootConfigClasses() {
		return new Class[] { BackConfig.class, DatabaseConfig.class, SecurityConfig.class };
	}
	@Override
	protected Class<?>[] getServletConfigClasses() {
		return new Class[] { MvcConfig.class };
	}

	@Override
	protected String[] getServletMappings() {
		return new String[] { "/" };
	}

	@Override
	protected Filter[] getServletFilters() {
		return null;
	}
}

SecurityWebApplicationInitializer.java】:是安全方面的啟動元件,與上面的WebApplicationInitializer繼承關係類似,可以啟動載入一些安全相關的配置和類。暫時不需要實現。

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

}

【com.aitongyi.web.back.controller.UserController】:使用者訪問控制器

import com.aitongyi.web.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * 使用者請求處理器
 * Created by admin on 16/8/6.
 */
@Controller
public class UserController {
    private static final Logger logger = LoggerFactory.getLogger(UserController.class);

    @Autowired
    private UserService userService;

    @RequestMapping(value = "/home", method = RequestMethod.GET)
    @PreAuthorize("isAuthenticated()")// isAuthenticated 如果使用者不是匿名使用者就返回true
    public String showHomePage() {
        try {
            userService.loadUserByUsername("admin");
            logger.info("load user ");
        }catch (Exception e){
            logger.error(e.getLocalizedMessage(), e);
        }

        return "/index/index";
    }
}


【日誌檔案】:logback.xml

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

     <appender name="default" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>/app/logs/back.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>3</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>[%-5level][%d{HH:mm:ss}] - [%logger{15}] - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>[%-5level][%d{HH:mm:ss}] - [%logger] - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <logger name="org.springframework.jdbc" level="DEBUG" additivity="false">
        <appender-ref ref="console"/>
    </logger>
    <logger name="org.springframework" level="INFO" additivity="false">
        <appender-ref ref="console"/>
    </logger>
    <root level="DEBUG">
        <appender-ref ref="console"/>
    </root>

</configuration>

【資料庫配置】:back.properties

#========= Mysql ============
jdbc.driver = com.mysql.jdbc.Driver
db.url = jdbc:mysql://127.0.0.1/web?useUnicode=true&characterEncoding=UTF-8
db.username = root
db.password = 123456
db.maxtotal = 150
db.minidle = 40
db.maxidle = 60

由於配置了資料庫資訊,所以資料庫是必須的,需要你安裝一個MySQL,然後建立一個web資料庫,建立一張users表,具體欄位見下面資料庫表建立檔案:(登入密碼是123456)

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL,
  `password` varchar(50) NOT NULL,
  `enabled` tinyint(1) NOT NULL,
  `create_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ix_username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
INSERT INTO `users` (`id`, `username`, `password`, `enabled`, `create_date`)
VALUES
	(1,'admin','e10adc3949ba59abbe56e057f20f883e',1,'2016-06-24 13:17:23'),
	(2,'user','e10adc3949ba59abbe56e057f20f883e',1,'2016-06-24 13:20:05');

另外還要建立一張許可權表:

CREATE TABLE `authorities` (
  `username` varchar(50) NOT NULL,
  `authority` varchar(50) NOT NULL,
  UNIQUE KEY `ix_auth_username` (`username`,`authority`),
  CONSTRAINT `fk_authorities_users` FOREIGN KEY (`username`) REFERENCES `users` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
寫入資料:
insert into(username, authority) value('admin','ROLE_ADMIN');


如果你想自己定義密碼,就使用
String password = md5Encoder.encodePassword(明文密碼, null);

來獲取一個數據庫中的密碼,將password替換資料庫的password就可以了。 4.2 【bean】專案

【com.aitongyi.web.bean.User】:使用者物件,主要是登陸時做安全驗證使用。

import java.util.Date;

/**
 * Created by admin on 16/8/8.
 */
public class User {
    private Integer id;
    private String username;
    private String password;
    private boolean enabled;
    private Date createDate;

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    public Integer getId() {
        return id;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}

【pom.xml】

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>web</artifactId>
        <groupId>com.aitongyi.web</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>bean</artifactId>


</project>



4.3 【dao】專案

DatabaseConfig.java】:資料庫配置類

import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

/**
 * Created by admin on 16/8/8.
 */

@Configuration
@EnableTransactionManagement
public class DatabaseConfig {
    private static final Logger logger = LoggerFactory.getLogger(DatabaseConfig.class);

    @Value("${jdbc.driver}")
    private String jdbcDriver;

    @Value("${db.url}")
    private String dbUrl;

    @Value("${db.username}")
    private String username;

    @Value("${db.password}")
    private String password;

    @Value("${db.maxtotal}")
    private Integer maxTotal;

    @Value("${db.minidle}")
    private Integer minIdle;

    @Value("${db.maxidle}")
    private Integer maxIdle;

    @Bean(destroyMethod = "close")
    public DataSource dataSource() {
        logger.info("mysql url:"+dbUrl);
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(jdbcDriver);
        dataSource.setUrl(dbUrl);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setMaxTotal(maxTotal);
        dataSource.setMinIdle(minIdle);
        dataSource.setMaxIdle(maxIdle);
        return dataSource;
    }

    @Bean
    public DataSourceTransactionManager txManager() {
        return new DataSourceTransactionManager(dataSource());
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        return sessionFactory.getObject();
    }
}
UserMapper.java】:資料庫持久層介面,主要是Mybatis管理
mport com.aitongyi.web.bean.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

/**
 * 使用者資料對映
 * Created by admin on 16/8/8.
 */
public interface UserMapper {

    @Select(value="select username,password,enabled from users where username = #{username}")
    User loadUserByUsername(@Param("username") String username);
    @Insert(value="insert into users (username, password, enabled, create_date) value(#{username},#{password},#{enabled},#{createDate})")
    void saveUser(User user);
}

【pom.xml】
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>web</artifactId>
        <groupId>com.aitongyi.web</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>dao</artifactId>


    <dependencies>
        <dependency>
            <groupId>com.aitongyi.web</groupId>
            <artifactId>bean</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>
</project>

4.4 【service】專案

【UserService】:使用者服務介面

import com.aitongyi.web.bean.User;
import com.aitongyi.web.dao.mapper.UserMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 使用者服務介面
 *
 */
@Service
public class UserService {
    private static final Logger logger = LoggerFactory.getLogger(UserService.class);
   @Autowired
   private UserMapper userMapper;


    @Transactional
    public User loadUserByUsername(String username) {
        return userMapper.loadUserByUsername(username);
    }
    
    @Transactional
    public void saveUser(User user) {
        userMapper.saveUser(user);
//        測試異常後資料是否回滾
//        getError();
    }

    private void getError() {
        int i = 1 / 0;
        logger.info("i:{}" , i);
    }
}

4.5 新增git過濾檔案

右鍵選擇專案,新增一個過濾檔案,在檔案中能匹配上的檔案將不會通過版本控制軟體進行版本控制。

到目前為止,專案的所有檔案都已經建立完成,我們點選執行按鈕,啟動專案,輸入使用者名稱:admin,密碼:123456,登入,就能看到登入成功

如果你會問,我們沒有寫登入驗證的程式碼,為什麼就自動登入了呢?你試著把密碼輸錯,你會發現你登入不了了!就是這麼神奇!

其實這是我們使用SpringSecurity安全框架的原因,安全框架自動會幫我們做一切登入驗證的事!你看看日誌中有這麼一段:

Executing prepared SQL statement [select username,password,enabled from users where username = ?]
這句sql你沒有寫過吧?這就是安全框架自己做的!關於安全框架的事,就說到這裡,展開了十篇文章不一定講完,還是以後再寫吧!

以上內容其實就已經搭建完成一個基本的零配置框架,今天就寫到這裡,由於時間的關係,我會繼續補上以下內容:

1. 可以通過加入任務排程配置來執行任務排程。

2. 可以加入redis快取來實現快取管理。

3. 可以整合shiro安全框架,也可以自己寫(個人覺得目前的安全框架文件不全、配置繁瑣、使用複雜)

4. 登入頁面、首頁樣式需要調整


目錄