编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

Spring Boot 一个极简且完整的后台框架

wxchong 2024-08-03 02:25:08 开源技术 45 ℃ 0 评论

一个完整的极简后台框架,方便做小项目的时候可以快速开发。

这里面多贴图片和代码,做个参考吧,代码可以下载下来自己看看,里面这套后台模板不错,喜欢的拿去。

先放几张图

image

image

image

项目介绍

SpringBoot,实现了一个极简单的后台框架

image

欢迎工作一到五年的Java工程师朋友们加入Java程序员开发: 721575865

群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!

项目配置

maven配置pox.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.moxi</groupId>
 <artifactId>moxi</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>
 <name>moxi</name>
 <description>mox</description>
 <parent>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-parent</artifactId>
 <version>1.5.2.RELEASE</version>
 <relativePath /> <!-- lookup parent from repository -->
 </parent>
 <properties>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
 <java.version>1.8</java.version>
 </properties>
 <dependencies>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-test</artifactId>
 <scope>test</scope>
 </dependency>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-devtools</artifactId>
 </dependency>
 <!-- mybatis -->
 <dependency>
 <groupId>org.mybatis.spring.boot</groupId>
 <artifactId>mybatis-spring-boot-starter</artifactId>
 <version>1.2.0</version>
 </dependency>
 <!-- mysql -->
 <dependency>
 <groupId>mysql</groupId>
 <artifactId>mysql-connector-java</artifactId>
 <scope>runtime</scope>
 </dependency>
 <!--thymeleaf -->
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-thymeleaf</artifactId>
 </dependency>
 <!--commons-io -->
 <dependency>
 <groupId>commons-io</groupId>
 <artifactId>commons-io</artifactId>
 <version>2.4</version>
 </dependency>
 </dependencies>
 <build>
 <plugins>
 <plugin>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-maven-plugin</artifactId>
 </plugin>
 </plugins>
 </build>
</project>

项目配置文件application.properties

#DataBase start

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/moxi?useUnicode=true&characterEncoding=UTF-8

spring.datasource.username=root

spring.datasource.password=Shu1shu2

spring.datasource.driver-class-name=com.mysql.jdbc.Driver

#DataBase end

#thymeleaf start

spring.thymeleaf.mode=HTML5

spring.thymeleaf.encoding=UTF-8

spring.thymeleaf.content-type=text/html

#开发时关闭缓存,不然没法看到实时页面

spring.thymeleaf.cache=false

#thymeleaf end

#uploadFileSize start

spring.http.multipart.maxFileSize=10Mb

spring.http.multipart.maxRequestSize=100Mb

#uploadFileSize end

项目分层

Controller层,追求极简,分页自己进行了一个简单封装

package com.moxi.controller;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import javax.servlet.http.HttpSession;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import com.moxi.model.NewsCategory;
import com.moxi.service.NewsCategoryService;
import com.moxi.util.PageUtil;
@Controller
@RequestMapping("/admin")
public class NewsController {
 @Autowired
 private NewsCategoryService newsCategoryService;
 @RequestMapping("/newsManage_{pageCurrent}_{pageSize}_{pageCount}")
 public String newsManage(@PathVariable Integer pageCurrent,@PathVariable Integer pageSize,@PathVariable Integer pageCount, Model model) {
 return "/news/newsManage";
 }
 /**
 * 文章分类列表
 * @param newsCategory
 * @param pageCurrent
 * @param pageSize
 * @param pageCount
 * @param model
 * @return
 */
 @RequestMapping("/newsCategoryManage_{pageCurrent}_{pageSize}_{pageCount}")
 public String newsCategoryManage(NewsCategory newsCategory,@PathVariable Integer pageCurrent,@PathVariable Integer pageSize,@PathVariable Integer pageCount, Model model) {
 //判断
 if(pageSize == 0) pageSize = 10;
 if(pageCurrent == 0) pageCurrent = 1;
 int rows = newsCategoryService.count(newsCategory);
 if(pageCount == 0) pageCount = rows%pageSize == 0 ? (rows/pageSize) : (rows/pageSize) + 1;
 //查询
 newsCategory.setStart((pageCurrent - 1)*pageSize);
 newsCategory.setEnd(pageSize);
 List<NewsCategory> list = newsCategoryService.list(newsCategory);
 //输出
 model.addAttribute("list", list);
 String pageHTML = PageUtil.getPageContent("newsCategoryManage_{pageCurrent}_{pageSize}_{pageCount}?name="+newsCategory.getName(), pageCurrent, pageSize, pageCount);
 model.addAttribute("pageHTML",pageHTML);
 model.addAttribute("newsCategory",newsCategory);
 return "/news/newsCategoryManage";
 }
 /**
 * 文章分类新增、修改跳转
 * @param model
 * @param newsCategory
 * @return
 */
 @GetMapping("newsCategoryEdit")
 public String newsCategoryEditGet(Model model,NewsCategory newsCategory) {
 if(newsCategory.getId()!=0){
 NewsCategory newsCategoryT = newsCategoryService.findById(newsCategory);
 model.addAttribute("newsCategory",newsCategoryT);
 }
 return "/news/newsCategoryEdit";
 }
 /**
 * 文章分类新增、修改提交
 * @param model
 * @param newsCategory
 * @param imageFile
 * @param httpSession
 * @return
 */
 @PostMapping("newsCategoryEdit")
 public String newsCategoryEditPost(Model model,NewsCategory newsCategory, @RequestParam MultipartFile[] imageFile,HttpSession httpSession) {
 for (MultipartFile file : imageFile) {
 if (file.isEmpty()) {
 System.out.println("文件未上传");
 } else {
 SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
 Date date = new java.util.Date();
 String strDate = sdf.format(date);
 String fileName = strDate + file.getOriginalFilename().substring(
 file.getOriginalFilename().indexOf("."),
 file.getOriginalFilename().length());
 String realPath = httpSession.getServletContext().getRealPath("/userfiles");
 System.out.println("realPath : "+realPath);
 try {
 FileUtils.copyInputStreamToFile(file.getInputStream(),new File(realPath, fileName));
 newsCategory.setImage("/userfiles/"+fileName);
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 }
 if(newsCategory.getId()!=0){
 newsCategoryService.update(newsCategory);
 } else {
 newsCategoryService.insert(newsCategory);
 }
 return "redirect:newsCategoryManage_0_0_0";
 }
}

Model层(pure类)

package com.moxi.model;

import java.sql.Date;

public class NewsCategory extends BaseObject {

private long id;

private String name;

private String description;

private String image;

private Date addDate;

private int state;

public long getId() {

return id;

}

public void setId(long id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getDescription() {

return description;

}

public void setDescription(String description) {

this.description = description;

}

public String getImage() {

return image;

}

public void setImage(String image) {

this.image = image;

}

public Date getAddDate() {

return addDate;

}

public void setAddDate(Date addDate) {

this.addDate = addDate;

}

public int getState() {

return state;

}

public void setState(int state) {

this.state = state;

}

}

Service层,一切追求极简,所以这里Mybatis用得是注解,我觉得注解也挺好用的。

package com.moxi.service;
import java.util.List;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import com.moxi.model.NewsCategory;
@Mapper
public interface NewsCategoryService {
 @Select("SELECT * FROM `moxi`.`news_category` where id = #{id};")
 NewsCategory findById(NewsCategory newsCategory);
 @Select({
 "<script>",
 "SELECT * FROM `moxi`.`news_category`",
 "WHERE state = 0",
 "<when test='name!=null'>",
 "AND name LIKE CONCAT('%',#{name},'%')",
 "</when>",
 "order by addDate desc limit #{start},#{end}",
 "</script>"
 })
 List<NewsCategory> list(NewsCategory newsCategory);
 @Select({
 "<script>",
 "SELECT count(*) FROM `moxi`.`news_category`",
 "WHERE state = 0",
 "<when test='name!=null'>",
 "AND name LIKE CONCAT('%',#{name},'%')",
 "</when>",
 "</script>"
 })
 int count(NewsCategory newsCategory);
 @Insert("INSERT INTO `moxi`.`news_category` (`id`, `name`, `description`, `image`, `addDate`, `state`) VALUES (null, #{name}, #{description}, #{image}, now(), 0);")
 int insert(NewsCategory newsCategory);
 @Update("UPDATE `moxi`.`news_category`SET `name` = #{name}, `description` = #{description}, `image` = #{image}, `state` = #{state} WHERE `id` = #{id};")
 int update(NewsCategory newsCategory);
}

View层,使用的thymeleaf的标签,挺好用的,本来打算全站用ajax,不过开发效率稍微慢了些。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>MOXI</title>
<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet" />
<link th:href="@{/font-awesome/css/font-awesome.css}" rel="stylesheet" />
<link th:href="@{/css/style.css}" rel="stylesheet" />
<link th:href="@{/css/plugins/iCheck/custom.css}" rel="stylesheet"/>
<link th:href="@{/css/plugins/footable/footable.core.css}" rel="stylesheet"/>
</head>
<body>
 <div id="wrapper">
 <nav class="navbar-default navbar-static-side" role="navigation" th:include="nav :: navigation"></nav>
 <div id="page-wrapper" class="gray-bg">
 <div class="border-bottom" th:include="header :: headerTop"></div>
 <div class="row wrapper border-bottom white-bg page-heading" th:fragment="headerNav">
 <div class="col-lg-10">
 <h2>文章分类</h2>
 <ol class="breadcrumb">
 <li>
 <a href="#">首页</a>
 </li>
 <li>
 <a>内容管理</a>
 </li>
 <li class="active">
 <strong>文章分类</strong>
 </li>
 </ol>
 </div>
 <div class="col-lg-2">
 </div>
 </div>
 <div class="wrapper wrapper-content animated fadeInRight">
 <div class="row">
 <div class="col-lg-12">
 <div class="ibox float-e-margins">
 <div class="ibox-title">
 <h5>搜索</h5>
 <div class="ibox-tools">
 <a class="collapse-link">
 <i class="fa fa-chevron-up"></i>
 </a>
 </div>
 </div>
 <div class="ibox-content" style="display: block;">
 <form action="newsCategoryManage_0_0_0">
 <div class="row">
 <div class="col-sm-3 m-b-xs">
 <input name="name" value="" th:value="${newsCategory.name}" placeholder="分类名称" class="form-control" type="text"/>
 </div>
 <div class="col-sm-1 m-b-xs">
 <button id="submitButton" class="btn btn-primary btn-block" type="submit"><i class="fa fa-search"></i> <strong>搜索</strong></button>
 </div>
 </div>
 </form>
 <div class="row">
 <div class="col-sm-6 m-b-xs">
 <a th:href="@{newsCategoryEdit}" class="btn btn-white btn-sm" data-toggle="tooltip" data-placement="left" title="" data-original-title="Refresh inbox"><i class="fa fa-plus"></i> 新增分类 </a>
 </div>
 <div class="col-sm-6 m-b-xs"></div>
 </div>
 </div>
 </div>
 </div>
 <div class="col-lg-12">
 <div class="ibox float-e-margins">
 <div class="ibox-title">
 <h5>文章列表</h5>
 <div class="ibox-tools">
 <a class="collapse-link">
 <i class="fa fa-chevron-up"></i>
 </a>
 </div>
 </div>
 <div class="ibox-content">
 <div class="table-responsive">
 <table class=" table table-hover" data-page-size="10">
 <thead>
 <tr>
 <th width="5%">ID</th>
 <th width="30%">名称 </th>
 <th width="40%">描述 </th>
 <th width="10%">添加时间</th>
 <th>操作</th>
 </tr>
 </thead>
 <tbody>
 <tr th:each="nc : ${list}">
 <td th:text="${nc.id}">Onions</td>
 <td th:text="${nc.name}">Onions</td>
 <td th:text="${nc.description}">Onions</td>
 <td th:text="${nc.addDate}">Onions</td>
 <td>
 <a th:href="@{'newsCategoryEdit?id='+${nc.id}}" title="修改"><i class="fa fa-edit text-navy"></i></a>
 <a th:href="@{'newsCategoryEdit?id='+${nc.id}}" title="修改"><i class="fa fa-trash-o text-navy"></i></a>
 </td>
 </tr>
 </tbody>
 <tfoot>
 <tr>
 <td colspan="7">
 <ul id="pageHTML" class="pagination pull-right"></ul>
 </td>
 </tr>
 </tfoot>
 </table>
 </div>
 </div>
 </div>
 </div>
 </div>
 </div>
 <div class="footer" th:include="footer :: copyright"></div>
 </div>
 </div>
 <!-- Mainly scripts -->
 <script th:src="@{/js/jquery-2.1.1.js}"></script>
 <script th:src="@{/js/bootstrap.min.js}"></script>
 <script th:src="@{/js/plugins/metisMenu/jquery.metisMenu.js}"></script>
 <script th:src="@{/js/plugins/slimscroll/jquery.slimscroll.min.js}"></script>
 <!-- Peity -->
 <script th:src="@{/js/plugins/peity/jquery.peity.min.js}"></script>
 <!-- Custom and plugin javascript -->
 <script th:src="@{/js/inspinia.js}"></script>
 <script th:src="@{/js/plugins/pace/pace.min.js}"></script>
 <!-- iCheck -->
 <script th:src="@{/js/plugins/iCheck/icheck.min.js}"></script>
 <!-- Peity -->
 <script th:src="@{/js/demo/peity-demo.js}"></script>
 <!-- FooTable -->
 <script th:src="@{/js/plugins/footable/footable.all.min.js}"></script>
 <!-- common -->
 <script th:src="@{/js/common.js}"></script>
 <script th:inline="javascript">
 var pageHTML = [[${pageHTML}]];
 $(document).ready(function () {
 $("#pageHTML").html(pageHTML);
 });
 </script>
</body>
</html>

分页封装,一切为了极简,做了个util类

package com.moxi.util;

public class PageUtil {

public static String getPageContent(String url,int pageCurrent,int pageSize,int pageCount){

if (pageCount == 0) {

return "";

}

String urlNew = url.replace("{pageSize}", pageSize+"").replace("{pageCount}", pageCount+"");

String first = urlNew.replace("{pageCurrent}", 1+"");

String prev = urlNew.replace("{pageCurrent}", (pageCurrent - 1)+"");

String next = urlNew.replace("{pageCurrent}", (pageCurrent + 1)+"");

String last = urlNew.replace("{pageCurrent}", pageCount+"");

StringBuffer html = new StringBuffer();

html.append("<li class=\"footable-page-arrow"+(pageCurrent<=1?" disabled":"")+"\"><a href=\""+(pageCurrent<=1?"#":first)+"\">?</a></li>");

html.append("<li class=\"footable-page-arrow"+(pageCurrent<=1?" disabled":"")+"\"><a href=\""+(pageCurrent<=1?"#":prev)+"\">?</a></li>");

for(int i = 0 ;i < pageCount; i++){

String urlItem = urlNew.replace("{pageCurrent}", (i+1)+"");

html.append("<li class=\"footable-page"+(((i+1) == pageCurrent)?" active":"")+"\"><a href=\""+urlItem+"\">"+(i+1)+"</a></li>");

}

html.append("<li class=\"footable-page-arrow"+(pageCurrent==pageCount?" disabled":"")+"\"><a href=\""+(pageCurrent==pageCount?"#":next)+"\">?</a></li>");

html.append("<li class=\"footable-page-arrow"+(pageCurrent==pageCount?" disabled":"")+"\"><a href=\""+(pageCurrent==pageCount?"#":last)+"\">?</a></li>");

return html.toString().replaceAll("null", "");

}

}

就这些,足够简单。包含登录、列表、分页、新增、修改、上传文件等……接下来会不断进行完善。

sql语句放到项目里面了。

欢迎工作一到五年的Java工程师朋友们加入Java程序员开发: 721575865

群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表