springboot

1,springboot入門

(1),配置文件

application.properties文件
文件格式:

#服務(wù)器的端口號(hào)
server.port=8081
#當(dāng)前web應(yīng)用的名稱
server.servlet.context-path=/demo

application.yml文件
文件格式:

#普通數(shù)據(jù)的配置
name: tom
#配置對象
person:
  name: jack
  age: 18
  addr: china
#行內(nèi)對象配置
#person: {name: tom,age: 18,addr: china}

#server:
#  port: 8082

#配置數(shù)組和集合(普通字符串)
city:
  - beijing
  - tianjing
  - shanghai

#city: [beijng,tianjing,shanghai]

student:
  - name: tom
    age: 18
    addr: beijng
  - name: jack
    age: 18
    addr: tianjing

#map配置
#map: {k1: v1, k2: v2}

map:
  key1: value1
  key2: value2
(2),注解的使用

@RestController 是組合注解 @ResponseBody + @Controller
@GetMapping 相當(dāng)于 @RequestMapping(value = "quick",RequestMethod.Get)
@ConfigurationProperties(prefix = "person") 用于配置文件注入數(shù)據(jù)

@Controller
@ConfigurationProperties(prefix = "person")
public class QuickController3 {

    private String name;
    private String addr;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    @RequestMapping("/quick3")
    @ResponseBody
    public String quick2(){
        //獲取配置文件
        return name+","+addr;
    }
}

用自定以文件給配置類注入數(shù)據(jù)
@Configuration 指定當(dāng)前類為配置類
@PropertySource("classpath:test.properties") 指定自定義文件的名稱和位置
@EnableConfigurationProperties(MyProperties.class) 開啟配置類的屬性注入功能

@Configuration
@PropertySource("classpath:test.properties")
@EnableConfigurationProperties(MyProperties.class)
@ConfigurationProperties(prefix = "test")
public class MyProperties {
    private int id;
    private String name;

    @Override
    public String toString() {
        return "MyProperties{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

test.properties文件

#對實(shí)體類對象MyProperties進(jìn)行屬性配置
test.id=110
test.name=test
(3),多環(huán)境配置

方法1:
application-dev.properties
application-prod.properties
application-test.properties
三種文件:
通過application.properties文件進(jìn)行激活

spring.profiles.active=test

方法2:
通過使用注解配置多環(huán)境配置類
@Profile(value = "dev") 指定多環(huán)境配類,放在config包下

@Configuration
@Profile(value = "dev") //指定多環(huán)境配類
public class DevDBConnector implements DBConnector{
    @Override
    public void configure() {
        System.out.println("數(shù)據(jù)庫配置環(huán)境——dev");
    }
}

通過application.properties文件進(jìn)行激活

spring.profiles.active=test

2,springboot整合Mybatis

(1),整合mybatis

連接數(shù)據(jù)庫的信息,添加到qpplication.properties文件中

#DB Configuration:
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/spring?
useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456

#數(shù)據(jù)源類型
#spring.datasource.type
#初始化連接數(shù)
spring.datasource.initialSize=20
#最小空閑數(shù)
spring.daasource.minIdle=10
#最大連接數(shù)
spring.datasource.maxActive=100

如果要用映射文件編寫mysql還下也要加上

#spring集成Mybatis環(huán)境
#pojo別名掃描包
mybatis.type-aliases-package=com.itheima.domain
#加載Mybatis映射文件
mybatis.mapper-locations=classpath:mapper/*Mapper.xml

如果用注解的什么都不用,按注解的正常方法寫

(2),springboot Date JPA

Discuss實(shí)體類
@Entity(name = "account") 該注解表示當(dāng)前實(shí)體類是與表有映射關(guān)系的實(shí)體類
@Id 該注解表示配置該屬性的字段為主鍵
@GeneratedValue(strategy = GenerationType.IDENTITY) 主鍵自增
@Column(name = "name") 對應(yīng)數(shù)據(jù)庫的名字

@Entity(name = "account")  //該注解表示當(dāng)前實(shí)體類是與表有映射關(guān)系的實(shí)體類
public class Discuss {
    @Id  //該注解表示配置該屬性的字段為主鍵
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Integer id;
    @Column(name = "name")
    String name;
    @Column(name = "money")
    Double money;
    
    Getter and Setter.....
}

然后定義接口DiscussRepository繼承 JpaRepository<Discuss,Integer> ,可以重寫方法,也可以自定義sql語句

public interface DiscussRepository extends JpaRepository<Discuss,Integer> {
    //查詢姓名非空的
    public List<Discuss> findByNameNotNull();

    @Query("select a from account a where a.id = ?1")
    public List<Discuss> getDiscussPage(Integer id, Pageable pageable);


    @Query(value = "select a from account a where a.id = ?1",nativeQuery = true)
    public List<Discuss> getDiscussPage2(Integer id, Pageable pageable);

    @Transactional
    @Modifying
    @Query("update account a set a.name = ?1 where a.id = ?2")
    public void update(String name, Integer id);
}
(3),springboot 整合Redis

首先在application.properties文件中配置連接

#配置redis連接
#redis服務(wù)器地址
spring.redis.host=127.0.0.1
#redis連接端口
spring.redis.port=6379
#連接密碼
spring.redis.password=

然后在實(shí)體類上添加注解
@RedisHash("persons") //在redis中開啟一塊空間
@Indexed //該屬性會(huì)在redis數(shù)據(jù)庫中生成二級(jí)索引

@RedisHash("persons")  //在redis中開啟一塊空間
public class Person {
    @Id
    private  String id;

    @Indexed        //該屬性會(huì)在redis數(shù)據(jù)庫中生成二級(jí)索引
    private String firstName;
    @Indexed
    private String lastName;
    private Address address;
    private List<Family> familyList;

    Getter and Setter.....
}

然后定義一個(gè)PersonRepository接口,并繼承 CrudRepository<Person,String>實(shí)現(xiàn)里面的方法

public interface PersonRepository extends CrudRepository<Person,String> {
    List<Person> findByLastname(String lastname);
    List<Person> findPersonByLastname(String Lastname, Pageable page);
    List<Person> findByFirstnameAndLastname(String firstname, String lastname);
    List<Person> findByAddress_City(String city);
    List<Person> findByFamilyList_Username(String username);
}
(4),springboot視圖技術(shù)

使用Thymeleaf模板
在application.properties文件中配置相關(guān)的設(shè)置

#模板緩存的:
spring.thymeleaf.cache=false
#模板編碼
spring.thymeleaf.encoding=UTF-8
#模板樣式
spring.thymeleaf.mode=HTML5
#指定模板頁面存放的路徑
spring.thymeleaf.prefix=classpath:/templates/
#指定模板的后綴
spring.thymeleaf.suffix=.html


#配置國際化文化的基礎(chǔ)名
spring.messages.basename=i18n.login

在資源文件resources下的templates下放入寫好的html頁面,在static頁面下放入需要的靜態(tài)資源
變量表達(dá)式:${}
選擇變量表達(dá)式:*{}
消息表達(dá)式:#{}
連接URL表達(dá)式:@{}
片段表達(dá)式:~{}

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1,shrink-to-fit=no">
    <title>用戶登錄界面</title>
    <link th:href="@{/login/css/bootstrap.min.css}" rel="stylesheet">
    <link th:href="@{/login/css/signin.css}" rel="stylesheet">
</head>
<body class="text-center">
<!--  用戶登錄form表單 -->
<form class="form-signin">
    <img class="mb-4" th:src="@{/login/img/login.jpg}" width="72" height="72">
    <h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">請登錄</h1>
    <input type="text" class="form-control"
           th:placeholder="#{login.username}" required="" autofocus="">
    <input type="password" class="form-control"
           th:placeholder="#{login.password}" required="">
    <div class="checkbox mb-3">
        <label>
            <input type="checkbox" value="remember-me"> [[#{login.rememberme}]]
        </label>
    </div>
    <button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.button}">登錄</button>
    <p class="mt-5 mb-3 text-muted">? <span th:text="${currentYear}">2018</span>-<span th:text="${currentYear}+1">2019</span></p>
    <a class="btn btn-sm" th:href="@{/toLoginPage(l='zh_CN')}">中文</a>
    <a class="btn btn-sm" th:href="@{/toLoginPage(l='en_US')}">English</a>
</form>
</body>
</html>

在resources下再放入i18n國際化的文件
login.properties
login_en_US.properties
login_zh.properties

login.tip=請登錄
login.username=用戶名
login.password=密碼
login.remember=記住我
login.button=登錄

login.tip=please sign in
login.username=Username
login.password=Password
login.remember=Remember me
login.button=Login

login.tip=請登錄
login.username=用戶名
login.password=密碼
login.remember=記住我
login.button=登錄

編寫語言轉(zhuǎn)換的配置類

@Configuration
public class MyLocalResolver implements LocaleResolver {
    @Override
    public Locale resolveLocale(HttpServletRequest httpServletRequest) {
        // 獲取頁面手動(dòng)切換傳遞的語言參數(shù)l
        String l = httpServletRequest.getParameter("l");
        // 獲取請求頭自動(dòng)傳遞的語言參數(shù)Accept-Language
        String header = httpServletRequest.getHeader("Accept-Language");
        Locale locale=null;
        // 如果手動(dòng)切換參數(shù)不為空,就根據(jù)手動(dòng)參數(shù)進(jìn)行語言切換,否則默認(rèn)根據(jù)請求頭信息切換
        if(!StringUtils.isEmpty(l)){
            String[] split = l.split("_");
            locale=new Locale(split[0],split[1]);
        }else {
            // Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7
            String[] splits = header.split(",");
            String[] split = splits[0].split("-");
            locale=new Locale(split[0],split[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest httpServletRequest, @Nullable HttpServletResponse httpServletResponse, @Nullable Locale locale) {

    }
    // 將自定義的MyLocalResolver類重新注冊為一個(gè)類型LocaleResolver的Bean組件
    @Bean
    public LocaleResolver localeResolver(){
        return new MyLocalResolver();
    }
}

在controller層用Java代碼打開頁面 項(xiàng)目day13_springboot01

3,springboot整合 spring MVC

(1),WebMvcConfigurer and HandlerInterceptor

使用框架中的接口WebMvcConfigurer來實(shí)現(xiàn)頁面的跳轉(zhuǎn),并且自定義攔截器

@Configuration
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //用戶請求/admin開頭路徑時(shí),判斷用戶是否登錄
        String requestURI = request.getRequestURI();
        System.out.println(requestURI);
        Object loginUser = request.getSession().getAttribute("loginUser");
        if(requestURI.startsWith("/admin")&& null == loginUser)
            response.sendRedirect("/toLoginPage");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        int i = Calendar.getInstance().get(Calendar.YEAR);
        request.setAttribute("currentYear",i);
    }
}

@Component
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //用戶請求/admin開頭路徑時(shí),判斷用戶是否登錄
        String requestURI = request.getRequestURI();
        System.out.println(requestURI);
        Object loginUser = request.getSession().getAttribute("loginUser");
        if(requestURI.startsWith("/admin")&& null == loginUser)
            response.sendRedirect("/toLoginPage");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        int i = Calendar.getInstance().get(Calendar.YEAR);
        request.setAttribute("currentYear",i);
    }
}
(2),springboot整合servlet三大組件

創(chuàng)建自定義的servlet等
MyServilet

@Component
@WebServlet("/myServlet")
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().print("hello myServlet");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

MyFilter

@Component
@WebFilter("/toLoginPage")
public class MyFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("自定義的MyFilter執(zhí)行了.....");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }
}

MyListener

@Component
@WebListener
public class MyListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("ContextInitialized執(zhí)行了");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("contextDestroyed執(zhí)行了");
    }
}

servlet三大組件的注冊

@Configuration
public class ServletConfig {
    /**
     * servlet組件的注冊
     */
    @Bean
    public ServletRegistrationBean getServlet(MyServlet myServlet){
        ServletRegistrationBean<MyServlet> myServletServletRegistrationBean = new ServletRegistrationBean<>(myServlet, "/myServlet");
        return myServletServletRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean getFilter(MyFilter myFilter){
        FilterRegistrationBean<MyFilter> myFilterFilterRegistrationBean = new FilterRegistrationBean<>(myFilter);
        myFilterFilterRegistrationBean.setUrlPatterns(Arrays.asList("/toLoginPage"));
        return myFilterFilterRegistrationBean;
    }

    @Bean
    public ServletListenerRegistrationBean getListener(MyListener myListener){
        ServletListenerRegistrationBean<MyListener> myListenerServletListenerRegistrationBean = new ServletListenerRegistrationBean<>(myListener);
        return myListenerServletListenerRegistrationBean;
    }
}
(3),文件的上傳和下載
@Controller
public class FileController {
    /**
     * 跳轉(zhuǎn)到 upload.html
     */

    @RequestMapping("/toUpload")
    public String toUpload(){
        return "upload";
    }

    /**
     * 實(shí)現(xiàn)文件上傳
     */
    @PostMapping("/uploadFile")
    public String uploadFile(MultipartFile[] fileUpload, Model model){
        //返回上傳成功的狀態(tài)信息
        model.addAttribute("uploadStatus","上傳成功");
        //上傳文件
        for (MultipartFile multipartFile : fileUpload) {
            //獲取上傳文件的后綴名
            String originalFilename = multipartFile.getOriginalFilename();
            //重新生成文件名
            String fileName = UUID.randomUUID() + "-" + originalFilename;
            //設(shè)置存儲(chǔ)目錄
            String dirPath = "D:/file/";
            //如果文件夾不存在,要?jiǎng)?chuàng)建
            File file = new File(dirPath);
            if(!file.exists()){
                file.mkdir();
            }
            try {
                multipartFile.transferTo(new File(dirPath));
            } catch (IOException e) {
                model.addAttribute("uploadStatus","上傳失敗");
            }
        }
        return "upload";
    }


    /**
     * 跳轉(zhuǎn)到download.html
     */
    @GetMapping("/toDownload")
    public String toDownload(){
        return "download";
    }
    /**
     * 文件下載
     */
    @GetMapping("/download")
    public ResponseEntity<byte[]> fileDownload(String filename){
        //指定要下載的文件路徑
        String dirPath = "D:/file/";
        //創(chuàng)建文件對象
        File file = new File(dirPath + File.separator + filename);
        //設(shè)置響應(yīng)頭
        HttpHeaders httpHeaders = new HttpHeaders();
        //通知瀏覽器以下載的方式打開
        httpHeaders.setContentDispositionFormData("attachment",filename);
        //定義以流的形式下載返回文件數(shù)據(jù)
        httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);

        try {
            return new ResponseEntity<>(FileUtils.readFileToByteArray(file),httpHeaders, HttpStatus.OK);
        } catch (IOException e) {
            e.printStackTrace();
            return new ResponseEntity<>(e.getMessage().getBytes(),HttpStatus.EXPECTATION_FAILED);
        }
    }

}

4,Springboot緩存管理

(1),springboot緩存注解

@EnableCaching 加在啟動(dòng)類
自定義實(shí)體類

@Entity(name = "account")
public class Account implements Serializable {
    @Id  //該注解表示配置該屬性的字段為主鍵
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Integer id;
    @Column(name = "name")  //一樣的時(shí)候可以不寫,不一樣的時(shí)候必須寫
    String name;
    @Column(name = "money")
    Double money;

    getter  and setter....
}

定義Repository

public interface AccountRepository extends JpaRepository<Account,Integer> {

    //根據(jù)id修改姓名
    @Modifying
    @Query("update account a set a.name = ?1 where a.id = ?2")
    public int updateAccount(String name,Integer id);
}

定義service

@Service
@Transactional
public class AccountService {
    @Autowired
    private AccountRepository accountRepository;

    /**
     * 查詢
     */
    @Cacheable(cacheNames = "account",unless ="#result==null")
    public Account findById(Integer id){
        Optional<Account> byId = accountRepository.findById(id);
        if(byId.isPresent()){
            return byId.get();
        }
        return null;
    }


    /**
     * 更新
     */
    @CachePut(cacheNames = "account",key = "#result.id")
    public Account update(Account account){
        int i = accountRepository.updateAccount(account.getName(), account.getId());
        Optional<Account> account1 = accountRepository.findById(account.getId());
        if(account1.isPresent()){
            return account1.get();
        }
        return null;
    }

    /**
     * 刪除
     */
    @CacheEvict(cacheNames = "account")
    public void delete(Integer id){
        accountRepository.deleteById(id);
    }
}

定義controller

@Controller
public class AccountController {
    @Autowired
    private AccountService accountService;

    /**
     * 查詢
     */
    @GetMapping("/get/{id}")
    @ResponseBody
    public Account findById(@PathVariable("id") Integer id){
        Account account = accountService.findById(id);
        System.out.println(account);
        return account;
    }

    /**
     * 更新
     */
    @GetMapping("/update/{id}/{name}")
    @ResponseBody
    public Account update(@PathVariable("id") Integer id,@PathVariable("name") String name){
        Account account = accountService.findById(id);
        account.setName(name);
        Account account1 = accountService.update(account);
        return account1;
    }

    /**
     * 刪除
     */
    @GetMapping("/delete/{id}")
    public void delete(@PathVariable("id") Integer id){
        accountService.delete(id);
    }
}
(2),springboot緩存API

APIService

@Service
@Transactional
public class ApiAccountService {
    @Autowired
    private AccountRepository accountRepository;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 查詢方法
     * @param id
     * @return
     */
    public Account findById(Integer id) {
        Object o = redisTemplate.opsForValue().get("account_" + "id");
        if(o != null){
            return (Account) o;
        }else {
            Optional<Account> account = accountRepository.findById(id);
            if(account.isPresent()){
                Account account1 = account.get();
                redisTemplate.opsForValue().set("account_"+id,account1);
                return account1;
            }
            return null;
        }
    }

    /**
     * 更新數(shù)據(jù)
     * @param account
     * @return
     */
    public Account updateAccount(Account account) {
        int i = accountRepository.updateAccount(account.getName(), account.getId());
        redisTemplate.opsForValue().set("account_"+account.getId(),account);
        return account;
    }

    public void deleteAccount(Integer id) {
        accountRepository.deleteById(id);
        redisTemplate.delete("account"+id);
    }
}

APIController

@Controller
@RequestMapping("/Api")
public class ApiAccountController {
    @Autowired
    private AccountService accountService;

    @Autowired
    private ApiAccountService apiAccountService;

    /**
     * 查詢
     */
    @GetMapping("/get/{id}")
    @ResponseBody
    public Account findById(@PathVariable("id") Integer id){
        Account account = apiAccountService.findById(id);
        System.out.println(account);
        return account;
    }

    /**
     * 更新
     */
    @GetMapping("/update/{id}/{name}")
    @ResponseBody
    public Account update(@PathVariable("id") Integer id,@PathVariable("name") String name){
        Account account = apiAccountService.findById(id);
        account.setName(name);
        Account account1 = apiAccountService.updateAccount(account);
        return account1;
    }

    /**
     * 刪除
     */
    @GetMapping("/delete/{id}")
    public void delete(@PathVariable("id") Integer id){
        apiAccountService.deleteAccount(id);
    }
}
(3),自定義序列化機(jī)制
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        //使用Json格式序列化對象,對緩存數(shù)據(jù)key和value進(jìn)行轉(zhuǎn)換
        Jackson2JsonRedisSerializer<Object> jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);

        //解決查詢轉(zhuǎn)換異常問題
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

        jsonRedisSerializer.setObjectMapper(objectMapper);

        //設(shè)置redisTemplate模板API的序列化方式為json
        redisTemplate.setDefaultSerializer(jsonRedisSerializer);
        return redisTemplate;
    }

    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        // 分別創(chuàng)建String和JSON格式序列化對象,對緩存數(shù)據(jù)key和value進(jìn)行轉(zhuǎn)換
        RedisSerializer<String> strSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jacksonSeial =
                new Jackson2JsonRedisSerializer(Object.class);
        // 解決查詢緩存轉(zhuǎn)換異常的問題
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSeial.setObjectMapper(om);

        // 定制緩存數(shù)據(jù)序列化方式及時(shí)效
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofDays(1))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(strSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jacksonSeial))
                .disableCachingNullValues();

        RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(config).build();
        return cacheManager;
    }
}

5,springboot整合Security

定義domian

@Entity(name = "t_customer")
public class Customer implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String username;
    private String password;
   
     getter and setter.....
}


@Entity(name = "t_authority ")
public class Authority implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String authority ;
   
    getter and setter.....
}

定義repository

public interface AuthorityRepository extends JpaRepository<Authority,Integer> {
    @Query(value = "select a.* from t_customer c,t_authority a,t_customer_authority ca where ca.customer_id=c.id and ca.authority_id=a.id and c.username =?1",nativeQuery = true)
    public List<Authority> findAuthoritiesByUsername(String username);

}

public interface CustomerRepository extends JpaRepository<Customer,Integer> {
    Customer findByUsername(String username);
}

使用User'DetailsService 方式進(jìn)行身份驗(yàn)證
定義service
custtomerService

@Service
public class CustomerService {
    @Autowired
    private CustomerRepository customerRepository;
    @Autowired
    private AuthorityRepository authorityRepository;
    @Autowired
    private RedisTemplate redisTemplate;

    // 業(yè)務(wù)控制:使用唯一用戶名查詢用戶信息
    public Customer getCustomer(String username){
        Customer customer=null;
        Object o = redisTemplate.opsForValue().get("customer_"+username);
        if(o!=null){
            customer=(Customer)o;
        }else {
            customer = customerRepository.findByUsername(username);
            if(customer!=null){
                redisTemplate.opsForValue().set("customer_"+username,customer);
            }
        }
        return customer;
    }
    // 業(yè)務(wù)控制:使用唯一用戶名查詢用戶權(quán)限
    public List<Authority> getCustomerAuthority(String username){
        List<Authority> authorities=null;
        Object o = redisTemplate.opsForValue().get("authorities_"+username);
        if(o!=null){
            authorities=(List<Authority>)o;
        }else {
            authorities=authorityRepository.findAuthoritiesByUsername(username);
            if(authorities.size()>0){
                redisTemplate.opsForValue().set("authorities_"+username,authorities);
            }
        }
        return authorities;
    }
}

UserdetailsService

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private CustomerService customerService;
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        // 通過業(yè)務(wù)方法獲取用戶及權(quán)限信息
        Customer customer = customerService.getCustomer(s);
        List<Authority> authorities = customerService.getCustomerAuthority(s);
        // 對用戶權(quán)限進(jìn)行封裝
        List<SimpleGrantedAuthority> list = authorities.stream().map(authority -> new SimpleGrantedAuthority(authority.getAuthority())).collect(Collectors.toList());
        // 返回封裝的UserDetails用戶詳情類
        UserDetails userDetails= new User(customer.getUsername(),customer.getPassword(),list);
        return userDetails;
    }
}

定義sercurityConfig
@EnableWebSecurity //@EnableGlobalAuthentication開啟自定義全局認(rèn)證

@EnableWebSecurity  //@EnableGlobalAuthentication開啟自定義全局認(rèn)證
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Qualifier("dataSource")
    @Autowired
    private DataSource dataSource;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //設(shè)置密碼編碼器
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        /*
        //使用內(nèi)存進(jìn)行身份認(rèn)證
        InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> authenticationManagerBuilderInMemoryUserDetailsManagerConfigurer = auth.inMemoryAuthentication().passwordEncoder(bCryptPasswordEncoder);
        authenticationManagerBuilderInMemoryUserDetailsManagerConfigurer.withUser("james").password(bCryptPasswordEncoder.encode("123")).roles("comment");
        authenticationManagerBuilderInMemoryUserDetailsManagerConfigurer.withUser("wade").password(bCryptPasswordEncoder.encode("456")).roles("vip");

        //使用jdbc進(jìn)行身份認(rèn)證
        JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> authenticationManagerBuilderJdbcUserDetailsManagerConfigurer = auth.jdbcAuthentication().passwordEncoder(bCryptPasswordEncoder);
        authenticationManagerBuilderJdbcUserDetailsManagerConfigurer.dataSource(dataSource);
        authenticationManagerBuilderJdbcUserDetailsManagerConfigurer.usersByUsernameQuery("select username,PASSWORD,STATUS from users where username = ?");
        authenticationManagerBuilderJdbcUserDetailsManagerConfigurer.authoritiesByUsernameQuery("select u.username, r.roleDesc from users u, role r,users_role ur where u.id = ur.userId and r.id=ur.roleId and u.username = ?");

         */

        //使用UserDetailService進(jìn)行身份驗(yàn)證
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/").permitAll()
                // 需要對static文件夾下靜態(tài)資源進(jìn)行統(tǒng)一放行
                .antMatchers("/login/**").permitAll()
                .antMatchers("/detail/common/**").hasRole("common")
                .antMatchers("/detail/vip/**").hasRole("vip")
                .anyRequest().authenticated()
                .and().formLogin();
        //自定義用戶登錄控制
        http.formLogin().loginPage("/userLogin").permitAll()
                .usernameParameter("name")
                .passwordParameter("pwd")
                .defaultSuccessUrl("/")
                .failureUrl("/userLogin?error");


        //自定義用戶推出
        http.logout().logoutUrl("/myLogout").logoutSuccessUrl("/");
    }
}

定義controller進(jìn)行操作

@Controller
public class FileController {


    @GetMapping("/detail/{type}/{path}")
    public String toDetail(@PathVariable("type") String type,@PathVariable("path") String path){
        return "detail/"+type+"/"+path;
    }

    @GetMapping("/userLogin")
    public String toLoginPage(){
        return "login/login";
    }

    @GetMapping("/getUserByContext")
    @ResponseBody
    public void getUser() {
        SecurityContext context = SecurityContextHolder.getContext();
        //獲取用戶相關(guān)信息
        Authentication authentication = context.getAuthentication();
        UserDetails principal = (UserDetails) authentication.getPrincipal();
        System.out.println(principal.getUsername());
    }
}

在resource文件下存放資源文件
day15_springboot02

6,springboot消息服務(wù)

配置qpplication.properties

#配置RabbitMQ消息中間的連接配置
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#配置RabbitMQ虛擬主機(jī)路徑/,可以省略
spring.rabbitmq.virtual-host=/

config

@Configuration
public class RabbitMQConfig {
    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }

}

service

@Service
public class RabbitMQService {
    /**
     * Publish/Subscribe工作模式接收,處理郵件業(yè)務(wù)
     * @param message
     */
    /**
    @RabbitListener(queues = "fanout_queue_email")
    public void psubConsumerEmail(Message message){
        byte[] body = message.getBody();
        String s = new String(body);
        System.out.println("郵件業(yè)務(wù)接收到消息:"+s);
    }
     */
    /**
     *Publish/Subscribe工作模式接收,處理短信業(yè)務(wù)
     * @param message
     */
    /**
    @RabbitListener(queues = "fanout_queue_sms")
    public void psubConsumerSms(Message message){
        byte[] body = message.getBody();
        String s = new String(body);
        System.out.println("短信業(yè)務(wù)接收到消息:"+s);
    }
     */

    /**
     *  **使用基于注解的方式實(shí)現(xiàn)消息服務(wù)
     * 1.1、Publish/Subscribe工作模式接收,處理郵件業(yè)務(wù)
     * @param user
     */
    @RabbitListener(bindings =@QueueBinding(value =@Queue("fanout_queue_email"), exchange =@Exchange(value = "fanout_exchange",type = "fanout")))
    public void psubConsumerEmailAno(User user) {
        System.out.println("郵件業(yè)務(wù)接收到消息: "+user);
    }
    /**
     * 1.2、Publish/Subscribe工作模式接收,處理短信業(yè)務(wù)
     * @param user
     */
    @RabbitListener(bindings =@QueueBinding(value =@Queue("fanout_queue_sms"),exchange =@Exchange(value = "fanout_exchange",type = "fanout")))
    public void psubConsumerSmsAno(User user) {
        System.out.println("短信業(yè)務(wù)接收到消息: "+user);
    }

    /**
     *  2.1、路由模式消息接收,處理error級(jí)別日志信息
     * @param message
     */
    @RabbitListener(
            bindings = @QueueBinding(
                    value = @Queue("routing_queue_error"),
                    exchange = @Exchange(value = "routing_exchange", type = "direct"),
                    key = "error_routing_key"))
    public void routingConsumerError(String message){
        System.out.println("接收到error級(jí)別日志消息"+message);
    }
    /**
     *  2.2、路由模式消息接收,處理info、error、warning級(jí)別日志信息
     * @param message
     */
    @RabbitListener(
            bindings = @QueueBinding(
                    value = @Queue("routing_queue_all"),
                    exchange = @Exchange(value = "routing_exchange", type = "direct"),
                    key = {"error_routing_key","info_routing_key","warning_routing_key"}))
    public void routingConsumerAll(String message){
        System.out.println("接收到info,error,warning等級(jí)別日志消息"+message);
    }

    /**
     *  3.1、通配符模式消息接收,進(jìn)行郵件業(yè)務(wù)訂閱處理
     * @param message
     */
    @RabbitListener(
            bindings =@QueueBinding(
                    value =@Queue("topic_queue_email"),
                    exchange =@Exchange(value = "topic_exchange",type = "topic"),
                    key = "info.#.email.#"))
    public void topicConsumerEmail(String message) {
        System.out.println("接收到郵件訂閱需求處理消息: "+message);
    }
    /**
     *  3.2、通配符模式消息接收,進(jìn)行短信業(yè)務(wù)訂閱處理
     * @param message
     */
    @RabbitListener(
            bindings =@QueueBinding(
                    value =@Queue("topic_queue_sms"),
                    exchange =@Exchange(value = "topic_exchange",type = "topic"),
                    key = "info.#.sms.#"))
    public void topicConsumerSms(String message) {
        System.out.println("接收到短信訂閱需求處理消息: "+message);
    }

}

test

@RunWith(SpringRunner.class)
@SpringBootTest
public class Day16Springboot01ApplicationTest {
    @Autowired
    private AmqpAdmin amqpAdmin;
    /**
     * 使用AmqpAdmin管理員API定制消息組件
     */
    @Test
    public void amqpAdmin() {
        // 1、定義fanout類型的交換器
        amqpAdmin.declareExchange(new FanoutExchange("fanout_exchange"));
        // 2、定義兩個(gè)默認(rèn)持久化隊(duì)列,分別處理email和sms
        amqpAdmin.declareQueue(new Queue("fanout_queue_email"));
        amqpAdmin.declareQueue(new Queue("fanout_queue_sms"));
        // 3、將隊(duì)列分別與交換器進(jìn)行綁定
        amqpAdmin.declareBinding(new Binding("fanout_queue_email",Binding.DestinationType.QUEUE,"fanout_exchange","",null));
        amqpAdmin.declareBinding(new Binding("fanout_queue_sms",Binding.DestinationType.QUEUE,"fanout_exchange","",null));
    }

    @Autowired
    private RabbitTemplate rabbitTemplate;
    /**
     * 1、Publish/Subscribe工作模式消息發(fā)送端
     */
    @Test
    public void psubPublisher() {
        User user=new User();
        user.setId(1);
        user.setUsername("石頭");
        rabbitTemplate.convertAndSend("fanout_exchange","",user);
    }
    /**
     *  2、Routing工作模式消息發(fā)送端
     */
    @Test
    public void routingPublisher() {
        rabbitTemplate.convertAndSend("routing_exchange","error_routing_key","routing send  error message");
    }

    /**
     *  3、Topcis工作模式消息發(fā)送端
     */
    @Test
    public void topicPublisher() {
        // 1、只發(fā)送郵件訂閱用戶消息
//        rabbitTemplate.convertAndSend("topic_exchange","info.email","topics send  email message");
        // 2、只發(fā)送短信訂閱用戶消息
//      rabbitTemplate.convertAndSend("topic_exchange","info.sms","topics send  sms message");
        // 3、發(fā)送同時(shí)訂閱郵件和短信的用戶消息
        rabbitTemplate.convertAndSend("topic_exchange","info.email.sms","topics send  email and sms message");
    }

}

7,消息處理

(1),無返回值的消息處理和有返回值的消息處理 在啟動(dòng)上加@EnableAsyn
@Service
public class MyASyncService {
    /**
     * 模擬無返回值的異步任務(wù)處理
     * @throws Exception
     */
    @Async
    public void sendSMS() throws Exception{
        long startTime = System.currentTimeMillis();
        Thread.sleep(5000);
        long endTime = System.currentTimeMillis();
        System.out.println("短信業(yè)務(wù)執(zhí)行完成耗時(shí),"+(endTime-startTime));
    }

    /**
     * 模擬有返回值的異步任務(wù)處理
     * @return
     * @throws Exception
     */
    @Async
    public Future<Integer> processA() throws Exception {
        System.out.println("開始分析并統(tǒng)計(jì)業(yè)務(wù)A數(shù)據(jù)...");
        Long startTime = System.currentTimeMillis();
        Thread.sleep(4000);
        // 模擬定義一個(gè)假的統(tǒng)計(jì)結(jié)果
        int count=123456;
        Long endTime = System.currentTimeMillis();
        System.out.println("業(yè)務(wù)A數(shù)據(jù)統(tǒng)計(jì)耗時(shí):" + (endTime - startTime));
        return new AsyncResult<Integer>(count);
    }
    @Async
    public Future<Integer> processB() throws Exception {
        System.out.println("開始分析并統(tǒng)計(jì)業(yè)務(wù)B數(shù)據(jù)...");
        Long startTime = System.currentTimeMillis();
        Thread.sleep(5000);
        // 模擬定義一個(gè)假的統(tǒng)計(jì)結(jié)果
        int count=654321;
        Long endTime = System.currentTimeMillis();
        System.out.println("業(yè)務(wù)B數(shù)據(jù)統(tǒng)計(jì)耗時(shí):" + (endTime - startTime));
        return new AsyncResult<Integer>(count);
    }
}



@Controller
public class MyAsyncController {
    @Autowired
    private MyASyncService myASyncService;

    @GetMapping("/sendSMS")
    public String sendSMS() throws Exception{
        long startTime = System.currentTimeMillis();
        myASyncService.sendSMS();
        long endTime = System.currentTimeMillis();
        System.out.println("主流耗時(shí),"+(endTime-startTime));
        return "success";
    }

    @GetMapping("/statistics")
    public String statistics() throws Exception {
        Long startTime = System.currentTimeMillis();
        Future<Integer> futureA = myASyncService.processA();
        Future<Integer> futureB = myASyncService.processB();
        int total = futureA.get() + futureB.get();
        System.out.println("異步任務(wù)數(shù)據(jù)統(tǒng)計(jì)匯總結(jié)果: "+total);
        Long endTime = System.currentTimeMillis();
        System.out.println("主流程耗時(shí): "+(endTime-startTime));
        return "success";
    }
}
(2),定時(shí)任務(wù) 在啟動(dòng)類上加@EnableScheduling
@Service
public class ScheduledTaskService {
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private Integer count1 = 1;
    private Integer count2 = 1;
    private Integer count3 = 1;

    @Scheduled(fixedRate = 60000)
    public void scheduledTaskImmediately() {
        System.out.println(String.format("fixedRate第%s次執(zhí)行,當(dāng)前時(shí)間為:%s", count1++, dateFormat.format(new Date())));
    }

    @Scheduled(fixedDelay = 60000)
    public void scheduledTaskAfterSleep() throws InterruptedException {
        System.out.println(String.format("fixedDelay第%s次執(zhí)行,當(dāng)前時(shí)間為:%s", count2++, dateFormat.format(new Date())));
        Thread.sleep(10000);
    }

    @Scheduled(cron = "0 * * * * *")
    public void scheduledTaskCron(){
        System.out.println(String.format("cron第%s次執(zhí)行,當(dāng)前時(shí)間為:%s",count3++, dateFormat.format(new Date())));
    }
}
(3),郵件發(fā)送

application.properties 中配置郵箱

#發(fā)件人郵箱服務(wù)器配置
spring.mail.host=smtp.qq.com
spring.mail.port=587
#配置個(gè)人qq賬戶和密碼
spring.mail.username=785846052@qq.com
spring.mail.password=duinweojybdubgaf
spring.mail.default-encoding=UTF-8
#郵箱服務(wù)超時(shí)間配置
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=3000
spring.mail.properties.mail.smtp.writetimeout=5000

sendemailService

@Service
public class SendEmailService {
    @Autowired
    private JavaMailSenderImpl mailSender;
    @Value("${spring.mail.username}")
    private String from;

    /**
     * 發(fā)送純文本郵件
     *
     * @param to      收件人地址
     * @param subject 郵件標(biāo)題
     * @param text    郵件內(nèi)容
     */
    public void sendSimpleEmail(String to, String subject, String text) {
        // 定制純文本郵件信息SimpleMailMessage
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(from);
        message.setTo(to);
        message.setSubject(subject);
        message.setText(text);
        try {
            // 發(fā)送郵件
            mailSender.send(message);
            System.out.println("純文本郵件發(fā)送成功");
        } catch (MailException e) {
            System.out.println("純文本郵件發(fā)送失敗 " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 發(fā)送復(fù)雜郵件(包括靜態(tài)資源和附件)
     * @param to           收件人地址
     * @param subject      郵件標(biāo)題
     * @param text         郵件內(nèi)容
     * @param filePath     附件地址
     * @param rscId        靜態(tài)資源唯一標(biāo)識(shí)
     * @param rscPath      靜態(tài)資源地址
     */
    public void sendComplexEmail(String to,String subject,String text,String filePath,String rscId,String rscPath){
        // 定制復(fù)雜郵件信息MimeMessage
        MimeMessage message = mailSender.createMimeMessage();
        try {
            // 使用MimeMessageHelper幫助類,并設(shè)置multipart多部件使用為true
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(from);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(text, true);
            // 設(shè)置郵件靜態(tài)資源
            FileSystemResource res = new FileSystemResource(new File(rscPath));
            helper.addInline(rscId, res);
            // 設(shè)置郵件附件
            FileSystemResource file = new FileSystemResource(new File(filePath));
            String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
            helper.addAttachment(fileName, file);
            // 發(fā)送郵件
            mailSender.send(message);
            System.out.println("復(fù)雜郵件發(fā)送成功");
        } catch (MessagingException e) {
            System.out.println("復(fù)雜郵件發(fā)送失敗 "+e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 發(fā)送模板郵件
     * @param to       收件人地址
     * @param subject  郵件標(biāo)題
     * @param content  郵件內(nèi)容
     */
    public void sendTemplateEmail(String to, String subject, String content) {
        MimeMessage message = mailSender.createMimeMessage();
        try {
            // 使用MimeMessageHelper幫助類,并設(shè)置multipart多部件使用為true
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(from);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(content, true);
            // 發(fā)送郵件
            mailSender.send(message);
            System.out.println("模板郵件發(fā)送成功");
        } catch (MessagingException e) {
            System.out.println("模板郵件發(fā)送失敗 "+e.getMessage());
            e.printStackTrace();
        }
    }
}

test

@RunWith(SpringRunner.class)
@SpringBootTest
public class SendEmailServiceTest {

    @Autowired
    private SendEmailService sendEmailService;
    @Autowired
    private TemplateEngine templateEngine;

    @Test
    public void sendSimpleMailTest() {
        String to="209962770@qq.com";
        String subject="【純文本郵件】標(biāo)題";
        String text="Spring Boot純文本郵件發(fā)送內(nèi)容測試.....";
        // 發(fā)送簡單郵件
        sendEmailService.sendSimpleEmail(to,subject,text);
    }

    @Test
    public void sendComplexEmailTest() {
        String to="209962770@qq.com";
        String subject="【復(fù)雜郵件】標(biāo)題";
        // 定義郵件內(nèi)容
        StringBuilder text = new StringBuilder();
        text.append("<html><head></head>");
        text.append("<body><h1>祝大家元旦快樂!</h1>");
        // cid為固定寫法,rscId指定一個(gè)唯一標(biāo)識(shí)
        String rscId = "img001";
        text.append("<img src='cid:" +rscId+"'/></body>");
        text.append("</html>");
        // 指定靜態(tài)資源文件和附件路徑
        String rscPath="E:\\圖片\\美女\\8.jpg";
        String filePath="E:\\Download\\哈哈.docx";
        // 發(fā)送復(fù)雜郵件
        sendEmailService.sendComplexEmail(to,subject,text.toString(),filePath,rscId,rscPath);
    }

    @Test
    public void sendTemplateEmailTest() {
        String to="209962770@qq.com";
        String subject="【模板郵件】標(biāo)題";
        // 使用模板郵件定制郵件正文內(nèi)容
        Context context = new Context();
        context.setVariable("username", "石頭");
        context.setVariable("code", "456123");
        // 使用TemplateEngine設(shè)置要處理的模板頁面
        String emailContent = templateEngine.process("emailTemplate_vercode", context);
        // 發(fā)送模板郵件
        sendEmailService.sendTemplateEmail(to,subject,emailContent);
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容