springboot CURD+thymeleaf+jpa+分页+redis的简单使用

springboot相较于springmvc来说,又精简了不少,这次做了个简单CURD小项目,简介一下:

基于springboot的简单增删查改
0,静态资源不太会用,所以页面不好看
1,使用thymeleaf模板(我不用这个模板时找不到resources下面的html或jsp,需要放在WEB-INF下面,然后在properties文件中配置前缀后缀,jsp需要另外导包)
2,使用jpa封装数据库操作(这个实在是太好用了,不用到数据库建表,不用写各种dao,service,mapper,一个类解决)
3,对controller设置全局异常处理,文件上传,带参重定向演示(controller里总不能把异常信息抛给客户吧)
4,简单使用redis(缓存加快效率,也降低数据库连接负担,不太懂这个)
5,分页和排序联合使用(mybatis有pagehelper插件,这里用的工具类,封装了按什么字段以什么顺序排序,以及如何分页的功能。使用的时候直接将pageable对象传入查询方法。
    分页功能转载地址:

https://blog.csdn.net/zsl129/article/details/52884571?locationNum=3&fps=1#commentBox)

--------------------------------------------------------------------------------------------------------------

首先是个效果图吧:

一,配置文件

A;pom.xml,如下,附上注释了,前后自动生成的文本去除了

<!-- 祖师包 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
    <!--     <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency> -->
        
    <!-- web包 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <!-- thymeleaf模板包,其包含spring-boot-starter包,而spring-boot-starter包
        又包含了spring-boot-starter-logging包,所以日志包不用,默认会使用logback -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        
        <!-- 开发体验包,支持热加载等。测试包就没上 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
        
        <!-- 数据库操作封装包jpa -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        
        <!-- sql不用多说,连接池没弄 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        
        <!-- mybatis的分页插件,这里没用 -->
        <!-- <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.2</version>
        </dependency> -->
        
        <!-- 用于管理静态资源,很好,不过我很多样式怎么写忘了很多 -->
        <!-- <dependency>
            <groupId>org.webjars.bower</groupId>
            <artifactId>jquery</artifactId>
            <version>2.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.webjars.bower</groupId>
            <artifactId>bootstrap</artifactId>
            <version>3.0.3</version>
        </dependency> -->
        
        <!-- 以下2个是redis的包 -->
        <!-- 第一个过时 被spring-boot-starter-data-redis代替【官网说的】 -->
        <dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-redis</artifactId>  
            <version>1.3.3.RELEASE</version>
        </dependency>  
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
            </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                </configuration>
            </plugin>
        </plugins>

    </build>

 

 

------------------------------------------------------------------------------------------

 

 

B;application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.show-sql=true

spring.http.multipart.max-file-size=10MB
spring.http.multipart.max-request-size=10MB

#most are by default
spring.thymeleaf.cache=false
spring.thymeleaf.content-type=text/html
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
#thymeleaf end

#many,choose one
spring.redis.database=0
#which your redis-server installed on
spring.redis.host=localhost
#default port
spring.redis.port=6379
#whether you set a password
spring.redis.password=fangfang
spring.redis.pool.max-active=8
#wait always
spring.redis.pool.max-wait=-1
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0

spring.redis.timeout=0

 

 

------------------------------------------------------------------------------------------------------

 

 

C;logback用的xml,命名也很重要,不然不会自动扫描到

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

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>
                %d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n
            </Pattern>
        </layout>
    </appender>
    <!-- additivity=false表示子Logger不会在父Logger里输出 -->
    <logger name="org.springframework.web" level="error" additivity="false">
        <appender-ref ref="STDOUT"/>
    </logger>

    <logger name="com.cl" level="debug" additivity="false">
        <appender-ref ref="STDOUT"/>
    </logger>

    <root level="error">
        <appender-ref ref="STDOUT"/>
    </root>

</configuration>

 

 

--------------------------------------------------------------------------------------------------------------------

 

 

二,包&类

首先,结构图如下,注意如果启动主类为父结构(com.cl),那么子结构(如com.cl.domain)会自动扫描到。

----------------------------------------------------------------------------------------------------

A;启动类

import org.apache.coyote.http11.AbstractHttp11Protocol;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;


@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

    // 大文件上传设置
    @Bean
    public TomcatEmbeddedServletContainerFactory tomcatEmbedded() {
        TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
        tomcat.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> {
            if ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol<?>)) {
                // -1 means unlimited
                ((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);
            }
        });
        return tomcat;
    }

}

 

 

-----------------------------------------------------------------------------------------------------------------

 

 

B;配置类

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.catalina.filters.RemoteIpFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//简单自定义过滤器的配置
@Configuration
public class WebConfiguration {
    @Bean
    public RemoteIpFilter remoteIpFilter() {
        return new RemoteIpFilter();
    }

    @Bean
    public FilterRegistrationBean testFilterRegistration() {

        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new MyFilter());
        registration.addUrlPatterns("/*");
        registration.addInitParameter("paramName", "paramValue");
        registration.setName("MyFilter");
        registration.setOrder(1);
        return registration;
    }

    public class MyFilter implements Filter {
        @Override
        public void destroy() {
            // TODO Auto-generated method stub
        }

        @Override
        public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain filterChain)
                throws IOException, ServletException {
            // TODO Auto-generated method stub
            HttpServletRequest request = (HttpServletRequest) srequest;
            System.out.println("this is MyFilter,url :" + request.getRequestURI());
            filterChain.doFilter(srequest, sresponse);
        }

        @Override
        public void init(FilterConfig arg0) throws ServletException {
            // TODO Auto-generated method stub
        }
    }
}

 

--------------------------------------------------------------------------------------------------------------

 

Redis配置

import java.lang.reflect.Method;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;

@Configuration
@EnableCaching
public class RedisConfiguration extends CachingConfigurerSupport{
    
    //方法及参数构成key
    @Bean
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuilder sb = new StringBuilder();
                sb.append(target.getClass().getName());
                sb.append("_"+method.getName());
                for (Object obj : params) {
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
    }
    
    //缓存管理
    @SuppressWarnings("rawtypes")
    @Bean
    public CacheManager cacheManager(RedisTemplate redisTemplate) {
        RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
        //设置缓存过期时间
        //rcm.setDefaultExpiration(60);//秒
        return rcm;
    }
    
    //redis模板,可以看出json格式
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
        StringRedisTemplate template = new StringRedisTemplate(factory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

}

 

-------------------------------------------------------------------------------------------------------

 

import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

//session共享
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)
public class RedisSessionConfiguration {

}

 

----------------------------------------------------------------------------------------------------------------------

 

C;实体类

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Student implements Serializable {

	private static final long serialVersionUID = 1L;
	@Id
	@GeneratedValue
	private Long id;
	@Column(nullable = false)
	private String name;
	public Long getId() {
		return id;
	}

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

	@Column(nullable = false)
	private String sex;
	@Column(nullable = false)
	private Integer age;
	//@Column(nullable = true, unique = true)unique=true不能和nullable=true一起用,否则只能允许一个非空存在
	@Column(nullable = false,unique=true)
	private String email;
	@Column(nullable = true)
	private String photoPath;

	public String getName() {
		return name;
	}

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

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getPhotoPath() {
		return photoPath;
	}

	public void setPhotoPath(String photo) {
		this.photoPath = photo;
	}

}

 

 

--------------------------------------------------------------------------------------------------

 

 

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

//有了这个不用service层了,方法命名要符合约定
public interface StudentRepo extends JpaRepository<Student, Long> {
    // Student findById(Long id);
    Page<Student> findAllByName(String name,Pageable pageable);
    //注意如果方法名为findByName,可能返回多个id导致异常,方法名一定要规范
    Integer countByName(String name);

}

 

----------------------------------------------------------------------------------------------

 

D;封装工具类

public class SortDto {
    // 排序方式
    private String pattern;
    // 排序字段
    private String field;
    //默认desc
    public SortDto(String field) {
        pattern = "desc";
        this.field = field;
    }

    public SortDto(String pattern, String field) {
        this.pattern = pattern;
        this.field = field;
    }

    public String getPattern() {
        return pattern;
    }

    public void setPattern(String pattern) {
        this.pattern = pattern;
    }

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }
}

 

 

-------------------------------------------------------------------------------

 

 

import org.springframework.data.domain.Sort;
//排序封装类
public class SortTools {
    // default
    public static Sort basicSort() {
        return basicSort("desc", "id");
    }

    public static Sort basicSort(String pattern, String field) {
        Sort sort = new Sort(Sort.Direction.fromString(pattern), field);
        return sort;
    }
    //这个方法允许我们以复杂的方式排序
    public static Sort basicSort(SortDto... dtos) {
        Sort result = null;
        for (int i = 0; i < dtos.length; i++) {
            SortDto sd = dtos[i];
            if (result == null)
                result = new Sort(Sort.Direction.fromString(sd.getPattern()), sd.getField());
            else
                result.and(new Sort(Sort.Direction.fromString(sd.getPattern()), sd.getField()));
        }
        return result;
    }
}

 

--------------------------------------------------------------------------------------------------

 

import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

//分页封装类
public class PageableTools {
    public static Pageable basicPage(Integer page, Integer size, SortDto... dtos) {
        Sort sort = SortTools.basicSort(dtos);
        page = (page == null || page < 0) ? 0 : page;
        size = (size == null || size <= 0) ? 10 : size;
        Pageable pageable = new PageRequest(page, size, sort);
        return pageable;
    }

    /**
     * 获取基础分页对象,每页条数默认15条 - 默认以id降序排序
     *
     * @param page
     *            获取第几页
     * @return
     */
    public static Pageable basicPage(Integer page) {
        return basicPage(page, 0, new SortDto("desc", "id"));
    }

    /**
     * 获取基础分页对象,每页条数默认15条
     *
     * @param page
     *            获取第几页
     * @param dtos
     *            排序对象数组
     * @return
     */
    public static Pageable basicPage(Integer page, SortDto... dtos) {
        return basicPage(page, 0, dtos);
    }

    /**
     * 获取基础分页对象,排序方式默认降序
     *
     * @param page
     *            获取第几页
     * @param size
     *            每页条数
     * @param orderField
     *            排序字段
     * @return
     */
    public static Pageable basicPage(Integer page, Integer size, String orderField) {
        return basicPage(page, size, new SortDto("desc", orderField));
    }

    /**
     * 获取基础分页对象 - 每页条数默认15条 - 排序方式默认降序
     *
     * @param page
     *            获取第几页
     * @param orderField
     *            排序字段
     * @return
     */
    public static Pageable basicPage(Integer page, String orderField) {
        return basicPage(page, 0, new SortDto("desc", orderField));
    }
}

 

E;controller类

 

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

//全局异常处理,2个注解
@ControllerAdvice
public class ControllerExceptionHandler {
    @ExceptionHandler(Exception.class)
    public String handleException(Exception e, RedirectAttributes redirectAttributes) {
        redirectAttributes.addFlashAttribute("message", e.getCause().getMessage());
        return "redirect:/status";
    }
}

 

------------------------------------------------------------------------------------------------------

 

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.cl.domain.Student;
import com.cl.domain.StudentRepo;
import com.cl.sortAndPage.PageableTools;
import com.cl.sortAndPage.SortDto;

@Controller

public class StudentController {

    //图片上传

    private static String UPLOADED_FOLDER = "D:\\upload\\";
    @Autowired
    private StudentRepo rep;

    @GetMapping("/")
    public String starting() {
        return "redirect:/index";
    }

    @GetMapping("/index")
    // 分页暂时只在首页实现了,
    public String index(Integer page, Model model) {
        // 第一次进入默认显示第一页
        if (page == null)
            page = 0;
        // 查找当前页面下的条目
        Page<Student> students = rep.findAll(PageableTools.basicPage(page, 0, new SortDto("asc", "id")));
        int total = (int) rep.count();
        int lastPage = (total + 10 - 1) / 10 - 1;
        model.addAttribute("students", students);
        // 点击某个跳转链接后,page传进来,再传回去,方便调整页面链接位置
        model.addAttribute("currentPage", page);
        // 最后一页还是每次都计算一下,防止删除操作导致页面不一致
        model.addAttribute("lastPage", lastPage);
        return "home";
    }

    @RequestMapping("/toEdit")
    public String toEdit(Long id, Model model) {
        Student student = rep.findOne(id);
        model.addAttribute("student", student);
        return "edit";
    }

    @RequestMapping("/edit")
    public String edit(@RequestParam("file") MultipartFile file, Student student) {
        if (file.isEmpty()) {
            rep.save(student);
            return "redirect:/index";
        }
        try {
            String oldPath = student.getPhotoPath();
            byte[] bytes = file.getBytes();
            Path path = Paths.get(UPLOADED_FOLDER + UUID.randomUUID().toString().replaceAll("-", "")
                    + file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")));
            Files.write(path, bytes);
            student.setPhotoPath(path.toString());
            rep.save(student);
            if (oldPath != null) {
                Path path2 = Paths.get(oldPath);
                Files.delete(path2);// 别忘了删除旧图片
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "redirect:/index";
    }

    @RequestMapping("/toAdd")
    public String toAdd() {
        return "add";
    }

    @RequestMapping("/add")
    public String add(@RequestParam("file") MultipartFile file, Student student) {
        if (file.isEmpty()) {
            rep.save(student);
            return "redirect:/index";
        }
        try {
            // 首先上传图片
            byte[] bytes = file.getBytes();
            String photoPath = UPLOADED_FOLDER + UUID.randomUUID().toString().replaceAll("-", "")
                    + file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
            Path path = Paths.get(photoPath);
            Files.write(path, bytes);
            // 然后设置图片路径
            student.setPhotoPath(photoPath);
            // 存入数据库
            rep.save(student);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "redirect:/index";
    }

    @RequestMapping("/toDel")
    public String delete(Long id) {
        String path = rep.findOne(id).getPhotoPath();
        if (path == null) {
            rep.delete(id);
            return "redirect:/index";
        }
        Path path2 = Paths.get(path);
        try {
            Files.deleteIfExists(path2);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        rep.delete(id);
        return "redirect:/index";
    }

    @RequestMapping("/toFind")
    public String toFind() {
        return "find";
    }

    // 下面2个本来可以通过一个方法用model等返回数据到html的,使用带参重定向的好处是uri中屏蔽了参数,更加安全
    @RequestMapping("/find")
    public String find(Integer page, String name, RedirectAttributes reAttr) {
        // 第一次进入默认显示第一页
        if (page == null)
            page = 0;
        // 查找当前页面下的条目
        Page<Student> students = rep.findAllByName(name, PageableTools.basicPage(page, 10, new SortDto("asc", "id")));
        // 方法命名约束
        int total = rep.countByName(name);
        int lastPage = (total + 10 - 1) / 10 - 1;
        reAttr.addFlashAttribute("students", students);
        reAttr.addFlashAttribute("currentPage", page);
        reAttr.addFlashAttribute("lastPage", lastPage);
        reAttr.addFlashAttribute("name", name);
        return "redirect:/findResult";
    }

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

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

    @RequestMapping("/toBack")
    public String back() {
        return "redirect:/index";
    }

}

 

页面类:

 

A: status.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<h1 th:text="${message}?${message}"></h1>

</html>

 

 

--------------------------------------------------

 

 

B: home.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
</head>
<body>
<h1>Student Manage</h1>
<div>
<table>
<thead>
<tr>
<th><a th:href="@{/toFind}">Find</a></th>
<th><a th:href="@{/toAdd}">Add</a></th>
</tr>
<tr>
<th>***</th>
<th>name</th>
<th>sex</th>
<th>age</th>
<th>email</th>
<th>photo</th>
<th>function1</th>
<th>function2</th>
</tr>
</thead>
<tbody th:if="${students}">if可以不用
<tr th:each="student:${students}">
<td th:text="${student.id}"/>
<td th:text="${student.name}"/>
<td th:text="${student.sex}"/>
<td th:text="${student.age}"/>
<td th:text="${student.email}?${student.email}:'null'"/>
<td><img th:if="${student.photoPath}" th:src="@{${student.photoPath}}" height="80px"/></td>
<td><a th:href="@{/toEdit(id=${student.id})}">Edit</a></td>
<td><a th:href="@{/toDel(id=${student.id})}">Delete</a></td>
</tr>
</tbody>
</table>
</div>
<!-- 下面是分页的实现 -->
<div>
<a th:href="@{/index(page=0)}">首页</a>
<a th:href="@{/index(page=${currentPage}-2)}" th:if="${currentPage ge 2}"><span th:text="${currentPage}-2"></span></a>
<a th:href="@{/index(page=${currentPage}-1)}" th:if="${currentPage ge 1}"><span th:text="${currentPage}-1"></span></a>
<a th:href="@{/index(page=${currentPage})}"><span th:text="${currentPage}"></span></a>
<a th:href="@{/index(page=${currentPage}+1)}" th:if="${currentPage+1 le lastPage}"><span th:text="${currentPage}+1"></span></a>
<a th:href="@{/index(page=${currentPage}+2)}" th:if="${currentPage+2 le lastPage}"><span th:text="${currentPage}+2"></span></a>
<a th:href="@{/index(page=${lastPage})}">尾页</a>
</div>
</body>
</html>

 

------------------------------------------------------------------

 

C: add.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<form method="post" th:action="@{/add}"  enctype="multipart/form-data">
        <input type="hidden" name="id"/>
        姓名:<input type="text" name="name" /><br />
        性别:<input type="text" name="sex"  /><br />
        年龄:<input type="text" name="age"  /><br />
        邮箱:<input type="text" name="email"  placeholder="nullable"/><br />
        图片:<input type="file" name="file"/><br />
        <input type="submit" value="Submit" />
</form>
</html>

 

---------------------------------------------------------------------------------------------

 

D: edit.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<form method="post" th:action="@{/edit}" th:object="${student}" enctype="multipart/form-data">
    <input type="hidden" name="id" th:value="*{id}" /><br /> <!-- 使用object后可以直接用*取属性-->
    姓名:<input type="text" name="name" th:value="*{name}" /><br />
        性别:<input type="text" name="sex" th:value="${student.sex}" /><br />
        年龄:<input type="text" name="age" th:value="${student.age}" /><br />
        邮箱:<input type="text" name="email" th:value="${student.email}" /><br />
        图片:<img th:src="@{${student.photoPath}}" height="100px"/><input type="file" name="file" /><br /><br/>
        <input type="submit" value="Submit" />
</form>
</html>

 

----------------------------------------------------------------------------------------------------

 

E: find.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<form method="post" th:action="@{/find}">
姓名:<input type="text" name="name"/>
<input type="submit" value="Submit"/>
</form>

</html>

 

 

--------------------------------------------------------------

 

 

F: findResult.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div>
<table>
<thead>
<tr>
<th>***</th>
<th>name</th>
<th>sex</th>
<th>age</th>
<th>email</th>
<th>photo</th>
<th>function1</th>
<th>function1</th>
</tr>
</thead>
<tbody>
<tr th:each="student:${students}" th:object="${student}">
<td th:text="*{id}"></td>
<td th:text="${name}"></td>
<td th:text="*{sex}"></td>
<td th:text="*{age}"></td>
<td th:text="*{email}"></td>
<td><img th:if="*{photoPath}" alt="" th:src="@{*{photoPath}}" height="100px"/></td>
<td><a th:href="@{/toEdit(id=*{id})}">Edit</a></td>
<td><a th:href="@{/toDel(id=*{id})}">Delete</a></td>
</tr>
</tbody>
<tfoot>
<tr>
<td><a th:href="@{/toBack}">Back to home</a></td>
</tr>
</tfoot>
</table>
</div>
<div>
<a th:href="@{/find(page=0,name=${name})}">首页</a>
<a th:href="@{/find(page=${currentPage}-2,name=${name})}" th:if="${currentPage ge 2}"><span th:text="${currentPage}-2"></span></a>
<a th:href="@{/find(page=${currentPage}-1,name=${name})}" th:if="${currentPage ge 1}"><span th:text="${currentPage}-1"></span></a>
<a th:href="@{/find(page=${currentPage},name=${name})}"><span th:text="${currentPage}"></span></a>
<a th:href="@{/find(page=${currentPage}+1,name=${name})}" th:if="${currentPage+1 le lastPage}"><span th:text="${currentPage}+1"></span></a>
<a th:href="@{/find(page=${currentPage}+2,name=${name})}" th:if="${currentPage+2 le lastPage}"><span th:text="${currentPage}+2"></span></a>
<a th:href="@{/find(page=${lastPage},name=${name})}">尾页</a>
</div>
</html>

 

----------------------------------

 

数据库不用自己建表,redis需要自己安装然后开启服务才能连接到,有windows版的。

总结:刚开始学springboot,感觉比ssm等精简很多,这里thymeleaf模板,jpa都非常好用,分页的实现也非常简单。

 

 

 


 

 


 


 

 

 

 


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值