springboot的web进阶知识(2)

4 篇文章 0 订阅
2 篇文章 0 订阅

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 abel533@gmail.com
 *
 * 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
可以逛逛顺便给我颗小星星,或者可以给我的博客点个赞,第二篇进阶博客不是一边学一边写的,是学完最后才写的,所以说不定有一些步骤会遗漏,发现的小伙伴可以给我留言,谢谢,继续加油!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值