初始SpringBoot,开发社区首页

1.1课程介绍

课程目标:

 对框架的深度理解,前提是要应用。灵活应变。

项目介绍:牛客网的的讨论功能,讨论社区。

JavaWeb重点在服务端,不在前端页面。前端熟悉Html常用标签,CSS ,js

首页:帖子列表,发帖,敏感词过滤---重点,算法

登陆,查看帖子内容,回帖,权限控制,对别人的回复进行评论

 登陆,发邮件,连接,验证码,账号密码判断,登陆查看个人主页,查看关注,被关注,曾经发帖,点击关注。

重点考虑性能的问题,如何不让服务器挂掉!!!

私信,回复私信

消息通知,消息队列-redis,多线程并发,消费者生产者模式。

全站搜索,专业搜索引擎,高性能,关键词高亮显示。如何中文分词,高亮显示,搜索引擎和数据库是如何同步数据的。

管理人使用:网站UV,活跃用户数。

如何提高性能,更加安全。

技术架构:

JavaEE

Spring 已经是实时上的行业标准了,包含多个框架。

Spring、SpringBoot Web应用框架

SpringMVC--如何处理浏览器的请求

MyBatis--如何访问数据库信息,用spring整合,SSM框架--实现项目基本功能,注册、登录、发帖、评论私信,时时刻刻。常规功能。

Redis--数据存在内存,高性能

Kafka--消息队列,发布消息

Elasticsearch--搜索引擎

用Spring整合,提高性能

Spring Security--提高系统安全

Spring Actuator -- 对线上系统进行监控,让运维人员随时监控系统状态

 

构建项目:对对项目进行创建、编译、测试、打包、生成文档,Maven

版本控制服务器:备份,版本控制,团队成员服务器

1.2搭建开发环境

 安装Maven 创建编译打包管理jar包

~家目录--系统盘;.m2

中央仓库:Maven仓库,镜像--第三方对Maven的拷贝,阿里云,私服仓库

下载Maven

修改为阿里云镜像

配置环境变量,安装maven,cmd或者IDEA

Spring Initializr : 把常用的的包进行了整合,可以批量导入

 配置项目基本信息,导入项目需要的jar,搜索功能,批量导入,创建一个JavaWeb项目

Spring Boot 的包中带有TomCat服务器

 我们搜索的的东西就是起步依赖

起步依赖,一组包的组合,少量的依赖导入大量的包

几乎不用配置就可以

端点控制--上线后

server.port=8080//配置Tomcat服务器端口
server.servlet.context-path=/community//项目访问路径

1.3Spring入门

Spring全家桶

Spring Framewprk:基础核心---spring---spring.io

Spring Boot:构建项目,更方便

Spring Cloud:微服务,拆分为若干子项目

Spring Cloud Data Flow:Spring做数据集成,很多客服端(手机,手表,智能穿戴。。。),采集数据,如何集成。

 IoC/AOP管理对象的一种思想,Spring中的Bean

Ioc:依赖注入,面向对象的管理思想

Aop:面向切面

Spring文档

https://www.docs4dev.com/docs/zh/spring-framework/5.1.3.RELEASE/reference/

 控制反转:传统的方法,创建一个对象A,创建一个对象B,在A中调用B,AB间发生耦合,不利于后期维护,通过控制反转实现bean间的耦合度。--通过依赖注入--基于Ioc容器---一个Bean工厂

IOC容器帮我们管理Bean,需要知道Bean有哪些以及bean的配置信息,通过bean的配置了解bean间的关系。

在SpringBoot中,启动一个web项目不仅帮助我们启动了一个TomCat还帮助我们创建了一个Spring 容器。创建容器后会自动扫描某些包下的某些bean,并装配

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration//自动配置
@ComponentScan(//自动的组件扫描
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
哪些会被扫描:
@ComponentScan--自动的组件扫描,会自动扫描配置类所在包及子包下的bean
bean上还要有@Controller注解
所以在bean上加Service/Componen/Repository/Controller,都是由Component实现

Service--业主组件

Componen--所有通用

Repository--数据库访问的组件

Controller--初级请求

 

@Service
public class AlphaService {
    public AlphaService() {
        System.out.print("构造器实例化");
    }

    @PostConstruct//该方法会在构造器后调用
    public void init(){
        System.out.print("初始化");
    }
    @PreDestroy//在对象销毁之前调用
    public void destory(){
        System.out.print("destory");
    }
}

 bean只被实例化一次,是单例模式,

通过加@Scpoe("singleton"、"prototype")--对bean是一个对象还是多个对象进行注释

"singleton"--默认是单例

"prototype"--每次访问都会创建一个new bean

用配置类装配第三方类

@Configuration
public class AlphaConfig {
    @Bean
    public SimpleDateFormat simpleDateFormat(){
        //返回的对象会被转配到IOC容器
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    }
}

 通过依赖注入的方式获取bean

不用getBean()

写一个属性,通过注解为属性注入,通过注解指定具体实现类

IoC是控制反转的意思,这是一种面向对象的编程思想。Spring采用依赖注入的方式,实现了IoC思想。
Spring Framework的功能:Transactions(事务处理)/Scheduling/Security
@Autowired用于注入Bean,@Qualifier用于声明Bean的名称,@Bean用于装配第三方的Bean,
@Configuration用于声明配置类。

1.4SpringMVC入门

Http:

超文本传输协议

用于传输Html等内容的应用层协议,底层是TCP

规定了浏览器和服务间如何通信和通信的数据格式

https://www.ieft.org

https://developer.mozilla.org/zh-CN/     火狐浏览器--支持中文

HTTP 流

当客户端想要和服务端进行信息交互时(服务端是指最终服务器,或者是一个中间代理),过程表现为下面几步:

  1. 打开一个TCP连接:TCP连接被用来发送一条或多条请求,以及接受响应消息。客户端可能打开一条新的连接,或重用一个已经存在的连接,或者也可能开几个新的TCP连接连向服务端。
  2. 发送一个HTTP报文:HTTP报文(在HTTP/2之前)是语义可读的。在HTTP/2中,这些简单的消息被封装在了帧中,这使得报文不能被直接读取,但是原理仍是相同的。
    GET / HTTP/1.1
    Host: developer.mozilla.org
    Accept-Language: fr
  3. 读取服务端返回的报文信息:
    HTTP/1.1 200 OK
    Date: Sat, 09 Oct 2010 14:28:02 GMT
    Server: Apache
    Last-Modified: Tue, 01 Dec 2009 20:18:22 GMT
    ETag: "51142bc1-7449-479b075b2891b"
    Accept-Ranges: bytes
    Content-Length: 29769
    Content-Type: text/html
    
    <!DOCTYPE html... (here comes the 29769 bytes of the requested web page)
  4. 关闭连接或者为后续请求重用连接。

当HTTP流水线启动时,后续请求都可以不用等待第一个请求的成功响应就被发送。然而HTTP流水线已被证明很难在现有的网络中实现,因为现有网络中有很多老旧的软件与现代版本的软件共存。因此,HTTP流水线已被在有多请求下表现得更稳健的HTTP/2的帧所取代。

请求由以下元素组成:

  • 一个HTTP的method,经常是由一个动词像GETPOST 或者一个名词像OPTIONSHEAD来定义客户端的动作行为。通常客户端的操作都是获取资源(GET方法)或者发送HTML form表单值(POST方法),虽然在一些情况下也会有其他操作。
  • 要获取的资源的路径,通常是上下文中就很明显的元素资源的URL,它没有protocolhttp://),domaindeveloper.mozilla.org),或是TCP的port (en-US)(HTTP一般在80端口)。
  • HTTP协议版本号。
  • 为服务端表达其他信息的可选头部headers
  • 对于一些像POST这样的方法,报文的body就包含了发送的资源,这与响应报文的body类似。

响应报文包含了下面的元素:

  • HTTP协议版本号。
  • 一个状态码(status code),来告知对应请求执行成功或失败,以及失败的原因。
  • 一个状态信息,这个信息是非权威的状态码描述信息,可以由服务端自行设定。
  • HTTP headers,与请求头部类似。
  • 可选项,比起请求报文,响应报文中更常见地包含获取的资源body。

 

服务器响应请求返回一个HTML文件,客户端解析HTML,发现需要引用了如图片,css,js等服务器资源,于是请求服务器,得到返回的CSS,js,图片等资源。

MVC三层架构

服务端三层架构:浏览器访问数据首先访问表现层,从表现层获取数据,表现层会调用业务层,处理业务,业务层调用数据层访问数据库数据。

MVC设计模式,和三层架构没有对应关系,主要解决表现层的问题

MVC是由DispatcherServlet调用:

 老版

 请求统一由前端控制器(front controller)DispatcherServlet处理,它会根据映射的注解,提供的路径找到controller,controller会把数据封装到model中,返回前端控制器;controller得到数据后会将试图模版(view template)中一些变量用model中的值进行替换,生成动态的网页

模版引擎:根据model数据动态生成HTML页面

 html文件大家都看的懂。

标准表达式;那些需要替换

判断预循环:model数据是否null,根据不同数据做不同处理,循环处理集合和数组等数据

模版布局:复用一样的区域。

 开发时模版的缓存不要开启,有缓存,,上线后可以开启缓存会降低服务器压力。

配置就是给某个Bean注入值。

spring boot文档:

https://docs.spring.io/spring-boot/docs/2.1.10.RELEASE/reference/htmlsingle/

Spring Boot Reference Guide

查看常用配置:

 Spring Boot Reference Guide

# THYMELEAF (ThymeleafAutoConfiguration)
spring.thymeleaf.cache=true # Whether to enable template caching.
spring.thymeleaf.check-template=true # Whether to check that the template exists before rendering it.
spring.thymeleaf.check-template-location=true # Whether to check that the templates location exists.
spring.thymeleaf.enabled=true # Whether to enable Thymeleaf view resolution for Web frameworks.
spring.thymeleaf.enable-spring-el-compiler=false # Enable the SpringEL compiler in SpringEL expressions.
spring.thymeleaf.encoding=UTF-8 # Template files encoding.
spring.thymeleaf.excluded-view-names= # Comma-separated list of view names (patterns allowed) that should be excluded from resolution.
spring.thymeleaf.mode=HTML # Template mode to be applied to templates. See also Thymeleaf's TemplateMode enum.
spring.thymeleaf.prefix=classpath:/templates/ # Prefix that gets prepended to view names when building a URL.
spring.thymeleaf.reactive.chunked-mode-view-names= # Comma-separated list of view names (patterns allowed) that should be the only ones executed in CHUNKED mode when a max chunk size is set.
spring.thymeleaf.reactive.full-mode-view-names= # Comma-separated list of view names (patterns allowed) that should be executed in FULL mode even if a max chunk size is set.
spring.thymeleaf.reactive.max-chunk-size=0B # Maximum size of data buffers used for writing to the response.
spring.thymeleaf.reactive.media-types= # Media types supported by the view technology.
spring.thymeleaf.render-hidden-markers-before-checkboxes=false # Whether hidden form inputs acting as markers for checkboxes should be rendered before the checkbox element itself.
spring.thymeleaf.servlet.content-type=text/html # Content-Type value written to HTTP responses.
spring.thymeleaf.servlet.produce-partial-output-while-processing=true # Whether Thymeleaf should start writing partial output as soon as possible or buffer until template processing is finished.
spring.thymeleaf.suffix=.html # Suffix that gets appended to view names when building a URL.
spring.thymeleaf.template-resolver-order= # Order of the template resolver in the chain.
spring.thymeleaf.view-names= # Comma-separated list of view names (patterns allowed) that can be resolved.

 封装请求和响应信息查看

 @RequestMapping(" /http ")
    public void http(HttpServletRequest request, HttpServletResponse response){
        //获取请求数据
        System.out.println(request.getMethod());
        System.out.println(request.getServletPath());
        Enumeration<String> enumeration = request.getHeaderNames();
        while(enumeration.hasMoreElements()){
            String name = enumeration.nextElement();
            String value = request.getHeader(name);
            System.out.println(name+":"+value);
        }
    }

 在SpringMVC中处理请求和响应的几种方式:

GET

POST

如何响应HTML---model&view

响应JSON数据(异步请求)

@Autowired
    private AlphaService alphaService;

    @RequestMapping("/hello")
    @ResponseBody
    public String sayHello() {
        return "Hello Spring Boot.";
    }

    @RequestMapping("/data")
    @ResponseBody
    public String getData() {
        return alphaService.find();
    }

    @RequestMapping("/http")
    public void http(HttpServletRequest request, HttpServletResponse response) {
        // 获取请求数据
        System.out.println(request.getMethod());
        System.out.println(request.getServletPath());
        Enumeration<String> enumeration = request.getHeaderNames();
        while (enumeration.hasMoreElements()) {
            String name = enumeration.nextElement();
            String value = request.getHeader(name);
            System.out.println(name + ": " + value);
        }
        System.out.println(request.getParameter("code"));

        // 返回响应数据
        response.setContentType("text/html;charset=utf-8");
        try (
                PrintWriter writer = response.getWriter();
        ) {
            writer.write("<h1>牛客网</h1>");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // GET请求

    // /students?current=1&limit=20
    @RequestMapping(path = "/students", method = RequestMethod.GET)
    @ResponseBody
    public String getStudents(
            @RequestParam(name = "current", required = false, defaultValue = "1") int current,
            @RequestParam(name = "limit", required = false, defaultValue = "10") int limit) {
        System.out.println(current);
        System.out.println(limit);
        return "some students";
    }

    // /student/123
    @RequestMapping(path = "/student/{id}", method = RequestMethod.GET)
    @ResponseBody
    public String getStudent(@PathVariable("id") int id) {
        System.out.println(id);
        return "a student";
    }

    // POST请求
    @RequestMapping(path = "/student", method = RequestMethod.POST)
    @ResponseBody
    public String saveStudent(String name, int age) {
        System.out.println(name);
        System.out.println(age);
        return "success";
    }

// 响应HTML数据
    @RequestMapping(path = "/teacher", method = RequestMethod.GET)
    public ModelAndView getTeacher() {
        //model层,打包好model,便于模版的熏染
        ModelAndView mav = new ModelAndView();//创建modelAndView对象,用于封装数据和视图显示
        mav.addObject("name", "张三");//封装数据
        mav.addObject("age", 30);
        mav.setViewName("/demo/view");//熏染视图模版
        return mav;
    }
 //另一种简单的模式
    @RequestMapping(path = "/school", method = RequestMethod.GET)
    public String getSchool(Model model) {//是DispatcherServlet调用该方法时分析需要model,就实例化该对象并传参
        //DispatcherServlet持有model数据和view视图,也能实现
        model.addAttribute("name", "北京大学");
        model.addAttribute("age", 80);
        return "/demo/view";
    }

// 响应JSON数据(异步请求)
    // 注册输入用户名,当光标离开文本框,失去焦点,此时会连接数据库判断用户名是否被占用,并返回true/false,但是页面没有被刷新
    //当前网页不刷新但是访问了一服务器并返回数据----异步请求
    // Java对象 -> JSON字符串 -> JS对象   用json可以实现跨语言信息传输

    @RequestMapping(path = "/emp", method = RequestMethod.GET)
    @ResponseBody
    public Map<String, Object> getEmp() {
        Map<String, Object> emp = new HashMap<>();
        emp.put("name", "张三");
        emp.put("age", 23);
        emp.put("salary", 8000.00);
        return emp;
    }

    @RequestMapping(path = "/emps", method = RequestMethod.GET)
    @ResponseBody
    public List<Map<String, Object>> getEmps() {
        List<Map<String, Object>> list = new ArrayList<>();
        //控制与循环
        Map<String, Object> emp = new HashMap<>();
        emp.put("name", "张三");
        emp.put("age", 23);
        emp.put("salary", 8000.00);
        list.add(emp);
        emp = new HashMap<>();
        emp.put("name", "李四");
        emp.put("age", 24);
        emp.put("salary", 9000.00);
        list.add(emp);
        emp = new HashMap<>();
        emp.put("name", "王五");
        emp.put("age", 25);
        emp.put("salary", 10000.00);
        list.add(emp);
        return list;
    }

 

HTTP协议规定了浏览器与服务器通信的四个步骤,依次是:建立连接、发送请求、接收响应、关闭连接
HTTP请求报文中,包含请求方式、请求路径、协议版本、消息头等内容
HTTP响应报文中,包含状态码状态名协议版本、消息头等内容
Spring MVC应用于表现层,降低了表现层代码的耦合度
Spring MVC的核心组件是DispatcherServlet,它负责分发所有的请求
Thymeleaf倡导自然模板,即以HTML文件为模板
Thymeleaf支持的语法有:标准表达式、判断与循环、模板的布局等
Thymeleaf生成动态HTML的前提是,你要为它提供模板文件与动态数据
@RequestMapping可以声明类或方法的访问路径,还可以声明请求的方式
@PathVariable可以将请求路径中的参数,绑定到控制器中方法的参数
@RequestParam可以将请求对象中的参数,绑定到控制器中方法的参数
@ResponseBody用于向浏览器响应字符串,同步异步
在控制器的方法中,我们可以直接使用Request、Response对象处理请求与响应
ModelAndView对象,既可以存储模型数据,又可以存储模板路径

1.5 MyBatis

MySQL的安装与配置——详细教程 - Winton-H - 博客园

配置:

改时区

 MyBatis

在SpringBoot中,前三个(SqlSessionFactory/SqlSession/XML配置文件)被整合

 mybatis – MyBatis 3 | 简介

mybatis-spring –    spring整合Mybatis

密码被加密过,salt是随机的字符串 ,为了防止用户的密码过于简单被破解,在用户密码后面拼接一个五位的随机字符串,然后进行加密

1.6 开发社区首页

开发流程:web解决浏览器和服务器间的请求和响应,任何功能可以拆分为若干请求和响应

一次请求的执行流程:先DAO-->Service-->Controller

 分布实现:

开发社区首页,显示前十个帖子

开发分页组件,分页显示所有帖子。

评论表

第一步:开发数据访问层dao,涉及实体类,dao接口和mapper.xml配置SQL

 entit----编写表实体类

dao----接口类--用@Mapper注解,编写dao接口对应的mapper配置文件,配置接口方法对应的SQL语句

第二步:开发Service层,业务层

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    public User findUserById(int id){
        return userMapper.selectById(id);
    }
    public User findUserByName(String username){
        return userMapper.selectByName(username);
    }
    public User findUserByEmail(String email){
        return userMapper.selectByEmail(email);
    }
}

就是嗲用dao层mapper接口方法。

第三部:视图层

动态模版页面,参数替换。

<!--map.get("user")->user.getHeaderUrl()  -->
<img th:src="${map.user.headerUrl}" class="mr-4 rounded-circle" alt="用户头像" style="width:50px;height:50px;">
<!--map.get("user")->user.getHeaderUrl()  -->
							<img th:src="${map.user.headerUrl}" class="mr-4 rounded-circle" alt="用户头像" style="width:50px;height:50px;">

<ul class="list-unstyled">                                                                                                                                                           
	<!-- 循环 each ,每次遍历到集合中的一个map-->                                                                                                                                                  
	<li class="media pb-3 pt-3 mb-3 border-bottom" th:each="map:${discussPosts}">                                                                                                    
		<a href="site/profile.html">                                                                                                                                                 
			<!--动态数据-->                                                                                                                                                              
			<!--map.get("user")->user.getHeaderUrl()  -->                                                                                                                            
			<!--/*@thymesVar id="user" type=""*/-->                                                                                                                                  
			<img th:src="${map.user.headerUrl}" class="mr-4 rounded-circle" alt="用户头像" style="width:50px;height:50px;">                                                              
		</a>                                                                                                                                                                         
		<div class="media-body">                                                                                                                                                     
			<h6 class="mt-0 mb-3">                                                                                                                                                   
				<!--utext   可以处理转义字符-->                                                                                                                                              
				<!--/*@thymesVar id="post" type=""*/-->                                                                                                                              
				<a href="#" th:utext="${map.post.title}">备战春招,面试刷题跟他复习,一个月全搞定!</a>                                                                                                   
				<!--根据帖子类型和状态决定置顶或者精华-->                                                                                                                                             
				<span class="badge badge-secondary bg-primary" th:if="${map.post.type==1}">置顶</span>                                                                                 
				<span class="badge badge-secondary bg-danger" th:if="${map.post.status==1}">精华</span>                                                                                
			</h6>                                                                                                                                                                    
			<div class="text-muted font-size-12">                                                                                                                                    
				<!--帖子的作者和发布时间-格式化-->                                                                                                                                                
				<u class="mr-3" th:utext="${map.user.username}">寒江雪</u> 发布于 <b th:text="${#dates.format(map.post.createTime,'yyyy-MM-dd HH:mm:ss')}">2019-04-15 15:32:18</b>         
				<ul class="d-inline float-right">                                                                                                                                    
					<li class="d-inline ml-2">赞 11</li>                                                                                                                              
					<li class="d-inline ml-2">|</li>                                                                                                                                 
					<li class="d-inline ml-2">回帖 7</li>                                                                                                                              
				</ul>                                                                                                                                                                
			</div>                                                                                                                                                                   
		</div>						                                                                                                                                                 
	</li>                                                                                                                                                                            
</ul>                                                                                                                                                                                
<!-- 分页 -->                                                                                                                                                                          
<!-- 分页 -->                                                                                                                              
<nav class="mt-5" th:if="${page.rows>0}">                                                                                                
	<ul class="pagination justify-content-center">                                                                                       
		<li class="page-item">                                                                                                           
			<a class="page-link" th:href="@{${page.path}(current=1)}">首页</a>                                                             
		</li>                                                                                                                            
		<li th:class="|page-item ${page.current==1?'disabled':''}|">                                                                     
			<a class="page-link" th:href="@{${page.path}(current=${page.current-1})}">上一页</a></li>                                       
		<li th:class="|page-item ${i==page.current?'active':''}|" th:each="i:${#numbers.sequence(page.from,page.to)}">                   
			<a class="page-link" href="#" th:text="${i}">1</a>                                                                           
		</li>                                                                                                                            
		<li th:class="|page-item ${page.current==page.total?'disabled':''}|">                                                            
			<a class="page-link" th:href="@{${page.path}(current=${page.current+1})}">下一页</a>                                            
		</li>                                                                                                                            
		<li class="page-item">                                                                                                           
			<a class="page-link" th:href="@{${page.path}(current=${page.total})}">末页</a>                                                 
		</li>                                                                                                                            
	</ul>                                                                                                                                
</nav>                                                                                                                                   

 这个一定要注释到不然报错:

<!--	<build>-->
<!--		<plugins>-->
<!--			<plugin>-->
<!--				<groupId>org.springframework.boot</groupId>-->
<!--				<artifactId>spring-boot-maven-plugin</artifactId>-->
<!--				<version>2.4.5</version>-->
<!--			</plugin>-->
<!--		</plugins>-->
<!--	</build>-->

 进一步开发分页功能:

分装分页组件 Page

根据点击的页码得到相应页面数据,显示,返回当前页页码,页面数据,总共有多少页数据。

//分装分页相关信息

    //当前页码
    private int current = 1;
    //显示上限
    private int limit = 10;
    //数据总数(计算总页数)
    private int rows;
    //查询路径(复用分页连接)
    private String path;

//    获取党旗前页的起始行
    public int getOffset(){
        return (current-1)*limit;//数据库从0行起
    }
//    获取总的页数
    public int getTotal(){
        if(rows%limit==0){
            return rows/limit;
        }else{
            return rows/limit+1;
        }
    }
//    获取起始页码
    public int getFrom(){
        int from = current-2;
        return from<1 ? 1:from;//不要小于1
    }

//    获取终止页码
    public int getTo(){
        int to = current+2;
        int total = getTotal();
        return to>total ? total:to;
    }
// 方法调用钱,SpringMVC会自动实例化Model和Page,并将Page注入Model.
        // 所以,在thymeleaf中可以直接访问Page对象中的数据
        //关于分页的配置,有page分装了方法
        page.setRows(discussPostService.findDiscussPostsRows(0));
        page.setPath("/index");

        //分页查询,前十条
        List<DiscussPost> discussPostList =  discussPostService.findDiscussPosts(0,page.getOffset(),page.getLimit());
        //帖子列表
        List<Map<String,Object>> discussPosts = new ArrayList<>();
        if(discussPostList != null){
            //遍历每个帖子
            //将帖子和用户相关联
            for(DiscussPost post : discussPostList){
                Map<String,Object> map = new HashMap<>();
                map.put("post",post);//帖子
//                System.out.println(post.getTitle());
                User user = userService.findUserById(post.getUserId());//发帖用户
//                System.out.println(user.getUsername());
                map.put("user",user);
                discussPosts.add(map);
            }
        }

        //添加到视图
        model.addAttribute("discussPosts",discussPosts);
        return "/index";

 复用分页:

<!-- 分页 -->
				<!-- 有数据才显示分页 -->
				<nav class="mt-5" th:if="${page.rows>0}">
					<ul class="pagination justify-content-center">
						<li class="page-item">
							<a class="page-link" th:href="@{${page.path}(current=1,limit=10)}">首页</a>
						</li>
						<!-- 当前页是1,就不能点击-->
						<li th:class="|page-item ${page.current==1?'disabled':''}|">
							<a class="page-link" th:href="@{${page.path}(current=${page.current-1})}">上一页</a></li>

						<!--生产一个连续的数组-->
						<!--点亮当前页-->
						<li th:class="|page-item ${i==page.current?'active':''}|" th:each="i:${#numbers.sequence(page.from,page.to)}">
							<a class="page-link" href="#" th:text="${i}">1</a>
						</li>
						<!--当前页是最后,就不能点击-->
						<li th:class="|page-item ${page.current==page.total?'disabled':''}|">
							<a class="page-link" th:href="@{${page.path}(current=${page.current+1})}">下一页</a>
						</li>
						<li class="page-item">
							<a class="page-link" th:href="@{${page.path}(current=${page.total})}">末页</a>
						</li>
					</ul>
				</nav>

1.7 项目调试技巧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值