springboot的web進階知識(2)

https://github.com/leechenxiang/imooc-springboot-starter這是課程老師的github,大家可以去down代碼。

6 配置devtools熱部署工具(IDEA)

熱部署:熱部署
devtools可以實現頁面熱部署(即頁面修改後會立即生效,
這個可以直接在application.properties文件中配置spring.thymeleaf.cache=false來實現)
實現類文件熱部署(類文件修改後不會立即生效),實現對屬性文件的熱部署。
即devtools會監聽classpath下的文件變動,並且會立即重啓應用(發生在保存時機),
注意:因爲其採用的虛擬機機制,該項重啓是很快的
(1)base classloader (Base類加載器):加載不改變的Class,例如:第三方提供的jar包。
(2)restart classloader(Restart類加載器):加載正在開發的Class。
爲什麼重啓很快,因爲重啓的時候只是加載了在開發的Class,沒有重新加載第三方的jar包。

(1)配置maven

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-devtools</artifactId>
   <!-- optional=true, 依賴不會傳遞, 該項目依賴devtools;
      之後依賴boot項目的項目如果想要使用devtools, 需要重新引入 -->
   <optional>true</optional>
</dependency>

(2)配置application.properties文件

#關閉緩存, 即時刷新
#spring.freemarker.cache=false
#spring.thymeleaf.cache=true

#熱部署生效
spring.devtools.restart.enabled=true
#設置重啓的目錄,添加那個目錄的文件需要restart
spring.devtools.restart.additional-paths=src/main/java
#爲mybatis設置,生產環境可刪除
restart.include.mapper=/mapper-[\\w-\\.]+jar
restart.include.pagehelper=/pagehelper-[\\w-\\.]+jar
#排除那個目錄的文件不需要restart
#spring.devtools.restart.exclude=static/**,public/**
#classpath目錄下的WEB-INF文件夾內容修改不重啓
#spring.devtools.restart.exclude=WEB-INF/**

(3)如果你是eclipse或者sts,應該就可以了,然後IDEA需要再配置一下

1) “File” -> “Settings” -> “Build,Execution,Deplyment” -> “Compiler”,選中打勾 “Build project automatically” 。
  2) 組合鍵:“Shift+Ctrl+Alt+/” ,選擇 “Registry” ,選中打勾 “compiler.automake.allow.when.app.running” 。

(4)修改自己的文件然後控制檯會顯示重新啓動

7 從配置文件讀取實體類數據

這裏有個問題沒解決,有思路的麻煩可以給我解答一下,就是Date方式的讀取

(1) 添加maven

<!--配置類與資源文件對應的依賴-->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-configuration-processor</artifactId>
   <optional>true</optional>
</dependency>

(2) User.properties配置文件(放在resources路徑下就可以)

com.zpr.autouser.name = 菲菲
com.zpr.autouser.password = 345
com.zpr.autouser.age = 34
#com.zpr.autouser.birthday = 2016-11-11

(3)在實體類上添加註解(我看到還有別的添加註解的方式,所以不僅僅這種方式配置)

@Component //神奇,不知道爲什麼@Configuration沒有用,表明與配置文件對應
@ConfigurationProperties(prefix = “com.zpr.autouser”) //這裏是配置文件的參數前面對應的前綴
@PropertySource(value = “classpath:user.properties”) //配置文件路徑

(4)創建一個控制層方法

@RequestMapping("/getAutoUser")
public IMoocJSONResult getAutoUser(){
    User bean = new User();
    BeanUtils.copyProperties(user,bean);
    return IMoocJSONResult.ok(bean);

}
返回數據:
{
  "status": 200,
  "msg": "OK",
  "data": {
    "name": "菲菲",
    "age": 34,
    "birthday": null
  },
  "ok": null
}

8 整合模板引擎(freemaker和thymeleaf)

敲黑板:前端頁面的要放在templates(動態模板)路徑下,兩種模板又分別放在自己的路徑下,好區分;

(1)添加maven

<!--添加freemaker模板-->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

(2)添加配置(application.properties)

#freemarker 靜態資源配置
#
############################################################
#設定ftl文件路徑
spring.freemarker.template-loader-path=classpath:/templates
#關閉緩存, 即時刷新, 上線生產環境需要改爲true
spring.freemarker.cache=false
spring.freemarker.charset=UTF-8
spring.freemarker.check-template-location=true
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=true
spring.freemarker.expose-session-attributes=true
spring.freemarker.request-context-attribute=request
spring.freemarker.suffix=.ftl

(3)添加index.ftl文件

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8" />
    <title></title>
</head>
<body>
FreeMarker模板引擎
<h1>${user.name}</h1>
<h1>${user.password}</h1>
<h1>${user.age}</h1>
</body>
</html>

(4)控制層訪問路徑方法

@Controller
@RequestMapping("ftl")
public class FreemarkerController {

    @Autowired
    private User user;
   
   @RequestMapping("/index")
    public String index(ModelMap map) {
        map.addAttribute("user", user);
        return "freemarker/index";
    }
}

(5)訪問結果

貼圖片得先保存,我這麼懶就直接貼頁面代碼

<!DOCTYPE html>
<html>
    <head lang="en">
        <meta charset="UTF-8" />
        <title></title>
    </head>
    <body>
FreeMarker模板引擎

        <h1>菲菲</h1>
        <h1>345</h1>
        <h1>34</h1>
    </body>
</html>

(6)thymleaf的配置和freemaker的配置大同小異

Maven

<!--添加thymeleaf模板-->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

配置

############################################################
#
# thymeleaf 靜態資源配置
#
############################################################
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.content-type=text/html
# 關閉緩存, 即時刷新, 上線生產環境需要改爲true
spring.thymeleaf.cache=false

#設定靜態文件路徑,js,css等
spring.mvc.static-path-pattern=/static/**

控制層方法:

@RequestMapping("/index")
   public String index(ModelMap map) {
       map.addAttribute("name", "thymeleaf-imooc");
       return "thymeleaf/index";
   }

頁面:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8" />
    <title></title>
</head>
<body>
Thymeleaf模板引擎
<h1 th:text="${name}">hello world~~~~~~~</h1>
</body>
</html>

顯示頁面代碼:

<!DOCTYPE html>
<html>
    <head lang="en">
        <meta charset="UTF-8" />
        <title></title>
    </head>
    <body>
Thymeleaf模板引擎

        <h1>thymeleaf-imooc</h1>
    </body>
</html>

9 整合MyBatis和實現分頁

這個是MyBatis插件作者的github,可以去看看:
https://github.com/abel533/Mapper/wiki

(1)添加maven

<!--mybatis-->
<dependency>
   <groupId>org.mybatis.spring.boot</groupId>
   <artifactId>mybatis-spring-boot-starter</artifactId>
   <version>1.3.1</version>
</dependency>
<!--mapper-->
<dependency>
   <groupId>tk.mybatis</groupId>
   <artifactId>mapper-spring-boot-starter</artifactId>
   <version>1.2.4</version>
</dependency>
<!--pagehelper-->
<dependency>
   <groupId>com.github.pagehelper</groupId>
   <artifactId>pagehelper-spring-boot-starter</artifactId>
   <version>1.2.3</version>
</dependency>
<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>druid</artifactId>
   <version>1.1.0</version>
</dependency>

<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>5.1.39</version>
</dependency>

(2)配置文件(數據庫要根據自己的)

############################################################
#
# 配置數據源相關  使用阿里巴巴的 druid 數據源
#
############################################################
spring.datasource.url=jdbc:mysql://localhost:3307/springboot1?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC&nullNamePatternMatchesAll=true
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.initial-size=1
spring.datasource.druid.min-idle=1
spring.datasource.druid.max-active=20
spring.datasource.druid.test-on-borrow=true
spring.datasource.druid.stat-view-servlet.allow=true


############################################################
#
# mybatis 配置
#
############################################################
# mybatis 配置
mybatis.type-aliases-package=com.zpr.pojo
mybatis.mapper-locations=classpath:mapper/*.xml
# 通用 Mapper 配置
mapper.mappers=com.zpr.utils.MyMapper
mapper.not-empty=false
mapper.identity=MYSQL
# 分頁插件配置
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql

(3)生成逆向工程

添加generatorConfig.xml文件,用來從數據庫生成對應的實體類等的,跟pom.xml在同一個路徑

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <context id="MysqlContext" targetRuntime="MyBatis3Simple" defaultModelType="flat">
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>

        <plugin type="tk.mybatis.mapper.generator.MapperPlugin">
            <property name="mappers" value="com.zpr.utils.MyMapper"/>
        </plugin>

        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3307/springboot1?useUnicode=true&amp;characterEncoding=UTF-8&amp;useSSL=false&amp;serverTimezone=UTC&amp;nullNamePatternMatchesAll=true"
                        userId="root"
                        password="123456">
        </jdbcConnection>

        <!-- 對於生成的pojo所在包 -->
        <javaModelGenerator targetPackage="com.zpr.pojo" targetProject="src/main/java"/>

      <!-- 對於生成的mapper所在目錄 -->
        <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources"/>

      <!-- 配置mapper對應的java映射 -->
        <javaClientGenerator targetPackage="com.zpr.mapper" targetProject="src/main/java"
                             type="XMLMAPPER"/>


      <table tableName="sys_user"></table>
       
    </context>
</generatorConfiguration>

在utils包下添加GeneratorDisplay.java類

package com.zpr.utils;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

public class GeneratorDisplay {

   public void generator() throws Exception{

      List<String> warnings = new ArrayList<String>();
      boolean overwrite = true;
      //指定 逆向工程配置文件
      File configFile = new File("generatorConfig.xml"); 
      ConfigurationParser cp = new ConfigurationParser(warnings);
      Configuration config = cp.parseConfiguration(configFile);
      DefaultShellCallback callback = new DefaultShellCallback(overwrite);
      MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
            callback, warnings);
      myBatisGenerator.generate(null);

   } 
   
   public static void main(String[] args) throws Exception {
      try {
         GeneratorDisplay generatorSqlmap = new GeneratorDisplay();
         generatorSqlmap.generator();
      } catch (Exception e) {
         e.printStackTrace();
      }
      
   }
}

還有一個MyMapper,用來給Mapper接口們繼承的

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014-2016 [email protected]
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.zpr.utils;

import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;

/**
 * 繼承自己的MyMapper
 *
 * @author liuzh
 * @since 2015-09-06 21:53
 */
public interface MyMapper<T> extends Mapper<T>, MySqlMapper<T> {
    //TODO
    //FIXME 特別注意,該接口不能被掃描到,否則會出錯
}

然後在GeneratorDisplay.java類右鍵運行生成相應的實體類和Mapper接口

(4)在應用入口類添加註解,就是我們啓動的那個類

//掃描mybatis mapper的包路徑
@MapperScan(basePackages = "com.zpr.mapper")
//掃描需要的所有包,包含一些自用的工具類包所在的路徑,後面那個是工具類,用來生成id的
@ComponentScan(basePackages = {"com.zpr","org.n3r.idworker"})

這裏我後續的操作是需要在Mapper接口類上面添加@Component,不然注入的時候總是劃紅線,雖然不影響,強迫症。
其他是MyBatis的CRUD自己看代碼吧。

10 定時任務

(1)在應用類添加註解

@EnableScheduling

(2)定時處理類

package com.zpr.task;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class TestTask {

   private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

   // 定義每過3秒執行任務
//    @Scheduled(fixedRate = 3000)
// @Scheduled(cron = "3-45 * * * * ?")
    public void reportCurrentTime() {
        System.out.println("現在時間:" + dateFormat.format(new Date()));
    }
}

啓動類會自動開始定時執行,這個是cron時間表達式轉換的工具網址: http://cron.qqe2.com/(記得年是不能用的,具體用法百度吧)

11 啓動異步任務

(1)在入口類添加註解

//啓動異步任務
@EnableAsync

(2)創建異步方法類

package com.zpr.task;

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;

import java.util.concurrent.Future;

@Component
public class AsyncTask {
   
   @Async
    public Future<Boolean> doTask11() throws Exception {
        long start = System.currentTimeMillis();
        Thread.sleep(1000);
        long end = System.currentTimeMillis();
        System.out.println("任務1耗時:" + (end - start) + "毫秒");
        return new AsyncResult<>(true);
    }
    
   @Async
    public Future<Boolean> doTask22() throws Exception {
        long start = System.currentTimeMillis();
        Thread.sleep(700);
        long end = System.currentTimeMillis();
        System.out.println("任務2耗時:" + (end - start) + "毫秒");
        return new AsyncResult<>(true);
    }
    
   @Async
    public Future<Boolean> doTask33() throws Exception {
        long start = System.currentTimeMillis();
        Thread.sleep(600);
        long end = System.currentTimeMillis();
        System.out.println("任務3耗時:" + (end - start) + "毫秒");
        return new AsyncResult<>(true); 
    }
}

(3)調用控制類:異步啓動時,時間取最長的那個,但是由於程序也需要消耗一些時間,所以會比最大的時間再大一點

package com.zpr.controller;

import com.zpr.task.AsyncTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.Future;

@RestController
@RequestMapping("tasks")
public class DoTask {
   
   @Autowired
    private AsyncTask asyncTask;
   
    @RequestMapping("test1")
    public String test1() throws Exception {
       
       long start = System.currentTimeMillis();
       
       Future<Boolean> a = asyncTask.doTask11();
       Future<Boolean> b = asyncTask.doTask22();
       Future<Boolean> c = asyncTask.doTask33();
       
       while (!a.isDone() || !b.isDone() || !c.isDone()) {
          if (a.isDone() && b.isDone() && c.isDone()) {
             break;
          }
       }
       
       long end = System.currentTimeMillis();
       
       String times = "任務全部完成,總耗時:" + (end - start) + "毫秒";
       System.out.println(times);
       
       return times;
    }
}

12 攔截器

(1)創建一個類繼承WebMvcConfigurerAdapter

package com.zpr.config;

import com.zpr.controller.interceptor.OneInterceptor;
import com.zpr.controller.interceptor.TwoInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {

   @Override
   public void addInterceptors(InterceptorRegistry registry) {
      /**
       * 攔截器按照順序執行
       */
      registry.addInterceptor(new OneInterceptor()).addPathPatterns("/one/**");
//      registry.addInterceptor(new TwoInterceptor()).addPathPatterns("/two/**")
//                                        .addPathPatterns("/one/**");

      super.addInterceptors(registry);
   }

}

(2)創建一個攔截器類

package com.zpr.controller.interceptor;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.zpr.pojo.IMoocJSONResult;
import com.zpr.utils.JsonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;


public class OneInterceptor implements HandlerInterceptor  {
   final static Logger log = LoggerFactory.getLogger(TwoInterceptor.class);

   /**
    * 在請求處理之前進行調用(Controller方法調用之前)
    */
   @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 
         Object object) throws Exception {
      
//    System.out.println("被one攔截,放行...");
      log.error("被one攔截,放行...");
      return true;
      
      /*if (true) {
         returnErrorResponse(response, IMoocJSONResult.errorMsg("被one攔截..."));
      }
      
      return false;*/
   }
   
   /**
    * 請求處理之後進行調用,但是在視圖被渲染之前(Controller方法調用之後)
    */
   @Override
   public void postHandle(HttpServletRequest request, HttpServletResponse response, 
         Object object, ModelAndView mv)
         throws Exception {
      // TODO Auto-generated method stub
      
   }
   
   /**
    * 在整個請求結束之後被調用,也就是在DispatcherServlet 渲染了對應的視圖之後執行
    * (主要是用於進行資源清理工作)
    */
   @Override
   public void afterCompletion(HttpServletRequest request, HttpServletResponse response, 
         Object object, Exception ex)
         throws Exception {
      // TODO Auto-generated method stub
      
   }
   
   public void returnErrorResponse(HttpServletResponse response, IMoocJSONResult result)
         throws IOException, UnsupportedEncodingException {
      OutputStream out=null;
      try{
          response.setCharacterEncoding("utf-8");
          response.setContentType("text/json");
          out = response.getOutputStream();
          out.write(JsonUtils.objectToJson(result).getBytes("utf-8"));
          out.flush();
      } finally{
          if(out!=null){
              out.close();
          }
      }
   }
}

(3)創建一個控制類方法測試

@Controller
@RequestMapping("one")
public class OneController {

   @RequestMapping("/index")
    public String index(ModelMap map) {
        map.addAttribute("name", "imooc22");
        return "thymeleaf/index";
    }
}

(4)日誌顯示

2019-02-01 08:32:50.497 ERROR 5860 --- [nio-8080-exec-1] c.z.c.interceptor.TwoInterceptor         : 被one攔截,放行...

這裏我沒有攔截,你們可以試着把另一個註釋去掉就可以看到攔截效果了。

如果你想看到我的拙略代碼,這裏是我的github:

https://github.com/momozpr/JavaCode/tree/com/springboot/zpr-springboot-demo
可以逛逛順便給我顆小星星,或者可以給我的博客點個贊,第二篇進階博客不是一邊學一邊寫的,是學完最後才寫的,所以說不定有一些步驟會遺漏,發現的小夥伴可以給我留言,謝謝,繼續加油!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章