SpringBoot项目复盘

简介: SpringBoot项目复盘

SpringBoot项目复盘



项目起始


  1. 确定数据库中的表、主键、各个字段及其代表的含义;确立好表与表之间的关联关系; (规范好字段的命名规则)**
  2. 按照数据库中表及其字段创建实体类及其属性;规范好命名规则
  3. 前端确定好页面长什么样,数据以什么格式交互
  4. 导入需要的各种依赖,以及做好自定义配置
  5. 准备好自己的后台模板,开始实现功能


实现各个功能


登录实现


  1. 在form表单中实现对账号、密码的输入。通过th:action="@{/user/login}"将表单数据提交至controller层中
  2. 在controller层通过匹配方法上的请求映射为@RequestMapping("/user/login")的方法。
  3. 在该方法中实现好对password的判断、是否username为空、username输入有误如何提示、数据如何回显至index页面….


@RequestMapping("/user/login")
public String login(Model model, HttpSession session,
                    @RequestParam("username") String username ,
                    @RequestParam("password") String password){
    if(username !=null && "123456".equals(password)){
        System.out.println("username= " + username);
        System.out.println("密码:" + password);
        //将值(用户名)传进来
        session.setAttribute("loginUser", username);    
        return "redirect:/main.html";
    }else{
        model.addAttribute("msg","用户名或密码错误!");
        return "index";
    }
}


后台实现数据回显的操作


<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>


如果后端数据判断显示为null或者密码错误。通过上述的语法就可以实现将数据回显出来,而不是一开始就显示数据


其中输入框提示的信息我们使用国际化的技术,能够实现页面的语言自由切换


<form class="form-signin" th:action="@{/user/login}">
    <img class="mb-4" src="https://getbootstrap.com/docs/4.0/assets/brand/bootstrap-solid.svg" alt="" width="72" height="72">
    <h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
    <!--消息回显,登录失败的情况
如果msg的值为空才显示
-->
    <p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
    <label for="inputEmail" class="sr-only">[#{login.username}]</label>
    <input type="email" id="inputEmail" class="form-control" th:name="username" th:placeholder="#{login.username}" required autofocus>
    <label for="inputPassword" class="sr-only">[#{login.password}]</label>
    <input type="password" id="inputPassword" th:name="password"  class="form-control" th:placeholder="#{login.password}" required>
    <div class="checkbox mb-3">
        <label>
            <input type="checkbox" value="remember-me"  th:text="#{login.remeber}">
        </label>
    </div>
    <button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.tip}"></button>
    <p class="mt-5 mb-3 text-muted">&copy; 2022-2023</p>
    <a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>
    <a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
</form>


通过<label for="inputEmail" class="sr-only">[#{login.username}]</label>显示提示语。


在配置中开启国际化

  • 在application.properties配置文件中,通过spring.messages.basename=i18n.login开启我们配置的国际化配置
  • 在自定义配置类中开启国际化方法


//往容器中注入组件
//自定义的国际化组件就会生效
@Bean
public LocaleResolver localeResolver(){
    return new MyLocaleResolver();
}

1.在config包下创建MyLocaleResolver类实现国际化的接口


public class MyLocaleResolver implements LocaleResolver {
    //解析请求
    @Override
    public Locale resolveLocale(HttpServletRequest httpServletRequest) {
        //获取请求的语言参数
        String language = httpServletRequest.getParameter("l");
        Locale locale = Locale.getDefault(); //如果没有就使用
        //如果请求的链接携带了国际化的参数
        if(!StringUtils.isEmpty(language)){
            //zh_CN
            String[] split = language.split("_");
            //国家 ,地区
           locale = new Locale(split[0], split[1]);
        }
        return locale;
    }
    @Override
    public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
    }
}

1.在resources文件夹下创建资源包login.properties、 login_en_US.properties 、 login_zh_CN.properties从而实现国际化的要求


springBoot001.png


登录开启拦截器


为了防止恶意的跳转,我们需要在用户未登录时自动拦截页面,使其跳转到登录页面,从而防止用户未登录就操作


1.首先在config包下的myConfig类中添加拦截器配置

//添加拦截器配置
@Override
public void addInterceptors(InterceptorRegistry registry) {
    //添加拦截器
    //登录拦截器 ,拦截哪些选择 ,排除哪些选择
    registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**").excludePathPatterns("/index.html",
                                                                                                      "/user/login","/","/css/**","/dist/**","/docs.4.0/**","/js/**","/img/**"
                                                                                                      ,"/index.html(l='zh_CN')","/index.html(l='en_US')","/user/LogOut");
}

1.在config包下同样创建LoginHandlerInterceptor类,使其实现拦截器接口。从而实现preHandle方法

public class LoginHandlerInterceptor implements HandlerInterceptor {
    //登录成功之后将用户的信息session传过来
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //登录成功,获取用过户的session
        Object loginUser = request.getSession().getAttribute("loginUser");
        if(loginUser == null) {
            request.setAttribute("msg", "没有权限,请登录");
            request.getRequestDispatcher("/index.html").forward(request, response);
            return false;
        }
        return true;
    }
}


首页实现


<!doctype html >
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="icon" th:href="@{/docs/4.0/assets/img/favicons/favicon.icof}">
    <title>Dashboard Template for Bootstrap</title>
    <link rel="canonical" href="https://getbootstrap.com/docs/4.0/examples/dashboard/">
    <!-- Bootstrap core CSS -->
    <link th:href="@{/dist/css/bootstrap.min.css}" rel="stylesheet">
    <!-- Custom styles for this template -->
    <link th:href="@{/docs/4.0/examples/dashboard/dashboard.css}" rel="stylesheet">
</head>
<body>
<!--顶部导航栏-->
    <div th:insert="~{common/common::topbar}"></div>
<!--侧边栏-->
<div class="container-fluid">
    <div class="row">
        <!--侧边栏-->
        <div th:insert="~{common/common::sidebar(active='main.html')}"></div>
        <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
            <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom">
                <h1 class="h2">Dashboard</h1>
                <div class="btn-toolbar mb-2 mb-md-0">
                    <div class="btn-group mr-2">
                        <button class="btn btn-sm btn-outline-secondary">Share</button>
                        <button class="btn btn-sm btn-outline-secondary">Export</button>
                    </div>
                    <button class="btn btn-sm btn-outline-secondary dropdown-toggle">
                        <span data-feather="calendar"></span>
                        This week
                    </button>
                </div>
            </div>
            <canvas class="my-4" id="myChart" width="900" height="380"></canvas>
        </main>
    </div>
</div>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script>window.jQuery || document.write('<script src="../static/js/vendor/jquery-slim.min.js"></script>')</script>
<script src="../static/js/vendor/popper.min.js"></script>
<script src="../static/dist/js/bootstrap.min.js"></script>
<!-- Icons -->
<script src="https://unpkg.com/feather-icons/dist/feather.min.js"></script>
<script>
    feather.replace()
</script>
<!-- Graphs -->
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.7.1/dist/Chart.min.js"></script>
<script>
    var ctx = document.getElementById("myChart");
    var myChart = new Chart(ctx, {
        type: 'line',
        data: {
            labels: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
            datasets: [{
                data: [15339, 21345, 18483, 24003, 23489, 24092, 12034],
                lineTension: 0,
                backgroundColor: 'transparent',
                borderColor: '#007bff',
                borderWidth: 4,
                pointBackgroundColor: '#007bff'
            }]
        },
        options: {
            scales: {
                yAxes: [{
                    ticks: {
                        beginAtZero: false
                    }
                }]
            },
            legend: {
                display: false,
            }
        }
    });
</script>
</body>
</html>


解释

通过后端登录成功将数据return "redirect:/main.html";重定向main.html,但是main.html这个地址是我们虚构的首页地址,以防止登录成功将用户信息传入导致用户信息泄露。


只需要在自定义配置中配置即可


@Configuration
public class MyConfig implements WebMvcConfigurer {
    /*
        配置根目录下的东西可以在这里配置
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/index.html").setViewName("index");
        /*将/main.html作为一个跳板,放置用户信息被揭密,*/
        registry.addViewController("/main.html").setViewName("dashboard");
    }
}


通过registry.addViewController("/main.html").setViewName("dashboard");调用main.html就可以跳转至dashboard首页


list页面实现


list页面作为数据显示的页面,它可以将我们后台传过来的数据通过Thymeleaf语法,将数据显示到后台


<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
  <h2>Section title</h2>
  <a class="btn btn-sm btn-success" th:href="@{/to/add}">添加员工</a>
  <div class="table-responsive">
    <table class="table table-striped table-sm">
      <thead>
        <tr>
          <th>id</th>
          <th>lastName</th>
          <th>Email</th>
          <th>gender</th>
          <th>department</th>
          <th>birth</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        <tr th:each="li : ${list}">
          <td th:text="${li.getId()}"></td>
          <td th:text="${li.getLastName()}"></td>
          <td th:text="${li.getEmail()}"></td>
          <td th:text="${li.getGender() == 0 ? '女' : '男'}" ></td>
          <td th:text="${li.getDepartment().getDepartmentName()}"></td>
          <td th:text="${#dates.format(li.getBirth(),'yyyy-MM-dd HH:mm:ss')}"></td>
          <td>
            <a class="btn btn-sm btn-primary" th:href="@{'/updateEmp/'+${li.getId()}}">修改</a>
            <a class="btn btn-sm btn-danger" th:href="@{'/deleteEmp/'+${li.getId()}}">删除</a>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</main>


后端通过用户点击员工管理


<li class="nav-item">
    <a th:class="${active=='list.html' ? 'nav-link active' :'nav-link'}" th:href="@{/list}">
        <span data-feather="users"></span>
        员工管理
    </a>
</li>

,请求就会跳转至controller匹配相应的请求映射


@Autowired
private EmployeeDao employeeDao;
@Autowired
private DepartmentDao departmentDao;
@RequestMapping("/list")
public String list(Model model){
    Collection<Employee> list = employeeDao.getAllEmployee();
    model.addAttribute("list",list);
    return "list";
}


后端通过Model将数据回显给list页面


在list页面。通过Thymeleaf语法<tr th:each="li : ${list}">将数据显示出来


<td th:text="${li.getId()}"></td>
  <td th:text="${li.getLastName()}"></td>
  <td th:text="${li.getEmail()}"></td>
  <td th:text="${li.getGender() == 0 ? '女' : '男'}" ></td>
  <td th:text="${li.getDepartment().getDepartmentName()}"></td>
  <td th:text="${#dates.format(li.getBirth(),'yyyy-MM-dd HH:mm:ss')}"></td>
  <td>
    <a class="btn btn-sm btn-primary" th:href="@{'/updateEmp/'+${li.getId()}}">修改</a>
    <a class="btn btn-sm btn-danger" th:href="@{'/deleteEmp/'+${li.getId()}}">删除</a>
  </td>
</tr>


这样,我们请求就能转发过来,用户就能看到数据


同时在list页面,我们也会有实现curd的跳转键


实现delete 和 update功能

对于delete功能,这里没什么好说的,仅仅通过点击用户后面对应的标签,将要删除的员工的id作为请求参数传到后端即可th:href="@{'/updateEmp/'+${li.getId()}}"后端通过匹配请求映射将功能实现


@RequestMapping("/deleteEmp/{id}")
public String deleteEmp(@PathVariable("id")Integer id){
    employeeDao.deleteEmp(id);
    return "redirect:/list";
}


实现update功能相较于delete功能是比较麻烦的


同样需要将要修改的员工id作为请求参数传入后端th:href="@{'/updateEmp/'+${li.getId()}}",然后后端通过查询,获取该员工的所有信息,然后通过Model将数据共享至update页面


@RequestMapping("/updateEmp/{id}")
public String update(Model model,@PathVariable("id") Integer id){
    System.out.println("id==" + id);
    Employee employee = employeeDao.getEmployeeById(id);
    System.out.println("emp == " + employee);
    model.addAttribute("emp",employee);
    Collection<Department> departments = departmentDao.getDepartments();
    model.addAttribute("departments",departments);
    return "/updateEmp";
}


在updateEmp页面,需要将数据回显出来


<!--表单提交-->
<form class="form-horizontal" role="form" th:action="@{/updateSucc}" method="post" >
    <input type="hidden" name="id" th:value="${emp.getId()}">
    <div class="form-group">
        <label for="lastName" class="col-sm-2 control-label">名字</label>
        <div class="col-sm-10">
            <input th:value="${emp.getLastName()}" type="text" class="form-control" id="lastName" name="lastName"
                   placeholder="请输入名字">
        </div>
    </div>
    <div class="form-group">
        <label for="lastname" class="col-sm-2 control-label">Email</label>
        <div class="col-sm-10">
            <input th:value="${emp.getEmail()}" type="text" class="form-control" id="Email" name="Email"
                   placeholder="请输入邮箱">
        </div>
    </div>
    <div class="form-group">
        <label for="gender">性别</label>
        <div class="form-check form-check-inline">
            <input th:checked="${emp.getGender()==1}" type="radio" class="form-check-input" name="gender" value="1" >
            <label class="form-check-label">男</label>
        </div>
        <div class="form-check form-check-inline">
            <input th:checked="${emp.getGender()==0}" type="radio" class="form-check-input" name="gender" value="0" >
            <label class="form-check-label">女</label>
        </div>
    </div>
    <div class="form-group">
        <label>Department</label>
        <select class="form-control" name="department.id">
            <option th:selected="${dept.getId()==emp.getDepartment().getId()}" th:each="dept:${departments}" th:text="${dept.getDepartmentName()}" th:value="${dept.getId()}"></option>
        </select>
    </div>
    <div class="form-group">
        <label for="birth" class="col-sm-2 control-label">birth</label>
        <div class="col-sm-10">
            <input th:value="${#dates.format(emp.getBirth(),'yyyy-MM-dd HH:mm')}" type="text" class="form-control" id="birth"  name="birth"
                   placeholder="请输入生日">
        </div>
    </div>
    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <div class="checkbox">
                <label>
                    <input type="checkbox"> 请记住我
                </label>
            </div>
        </div>
    </div>
    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <button type="submit" class="btn btn-default">登录</button>
        </div>
    </div>
</form>


1.通过隐藏域<input type="hidden" name="id" th:value="${emp.getId()}">可以将后端传入的信息获取到


2.因为我们共享数据时是通过model.addAttribute("emp",employee);,所以在获取,然后在<input th:value="${emp.getLastName()}" type="text" class="form-control" id="lastName" name="lastName" placeholder="请输入名字">中通过th:value="${emp.getLastName()}"就可以将数据显示到页面


3.对于复杂的比如department



<select class="form-control" name="department.id">
            <option th:selected="${dept.getId()==emp.getDepartment().getId()}" th:each="dept:${departments}" th:text="${dept.getDepartmentName()}" th:value="${dept.getId()}"></option>
</select>


可以先通过deparment.id获取全部的信息,然后通过匹配emp.getDepartment().getId()获取将表单展示出来。通过th:value="${dept.getId()}"将我们需要的数据显示到页面


4.然后通过请求form表单的th:action="@{/updateSucc}"提交表单至后端.


5.后端通过请求映射匹配到相应的请求方法

@PostMapping("/updateSucc")
public String updateSuccess(Employee employee){
    employeeDao.save(employee);
    return "redirect:/list";
}


然后进行修改,最后通过重定向将请求跳转至原来的页面


add功能实现


用户通过点击添加员工将请求发送到后端,后端通过请求映射匹配到相应的请求方法,实现添加功能

<a class="btn btn-sm btn-success" th:href="@{/to/add}">添加员工</a>
@GetMapping("/to/add")
public String addEmp(Model model){
    Collection<Department> departments = departmentDao.getDepartments();
    model.addAttribute("departments",departments);
    return "addEmp";
}

后台页面与update页面类似


目录
相关文章
|
6月前
|
前端开发 搜索推荐 Java
【Spring Boot】深度复盘在开发搜索引擎项目中重难点的整理,以及遇到的困难和总结
【Spring Boot】深度复盘在开发搜索引擎项目中重难点的整理,以及遇到的困难和总结
35 0
|
Java jenkins 应用服务中间件
价值不言而喻,SSM项目升级springBoot复盘,又是一个极小的细节
价值不言而喻,SSM项目升级springBoot复盘,又是一个极小的细节
117 0
价值不言而喻,SSM项目升级springBoot复盘,又是一个极小的细节
|
Java 应用服务中间件 文件存储
springboot创建文件无法读取问题复盘
springboot创建文件无法读取问题复盘
254 0
|
2月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
162 1
|
3月前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的服装商城管理系统
基于Java+Springboot+Vue开发的服装商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的服装商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
171 2
基于Java+Springboot+Vue开发的服装商城管理系统
|
3月前
|
前端开发 JavaScript Java
SpringBoot项目部署打包好的React、Vue项目刷新报错404
本文讨论了在SpringBoot项目中部署React或Vue打包好的前端项目时,刷新页面导致404错误的问题,并提供了两种解决方案:一是在SpringBoot启动类中配置错误页面重定向到index.html,二是将前端路由改为hash模式以避免刷新问题。
261 1
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
104 62
|
28天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
53 2
|
1月前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
3月前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的大学竞赛报名管理系统
基于Java+Springboot+Vue开发的大学竞赛报名管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的大学竞赛报名管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
227 3
基于Java+Springboot+Vue开发的大学竞赛报名管理系统