springboot spa根据entity类生成表_SpringBoot初体验

初入Java开发职场,接触好多开源框架,觉得有必要把知识累积下来。接下来就以一个小小的Demo做为SpringBoot学习的开篇吧,今后会围绕这个Demo把全部的知识穿插进去。

第一步:创建空工程

利用IDEA创建一个Spring Initializr工程,工程组、名、版本号等信息如下图:

1df4996ae7e8b37fe3107ed190ade43d.png

91ac44cf5b7807aa8b2daf5f26d54adf.png

在Dependencies部分仅仅选择Web模块就好,其他依赖的包后续会手动添加

f7771ad07abea2277254a27a5955576f.png

接下来我们看看新创建出来的工程pom.xml文件中都导入了哪些依赖,此处仅仅展示了依赖的包,分别为:Spring web starter和test模块,如下:

<dependency>    <groupId>org.springframework.bootgroupId>    <artifactId>spring-boot-starter-webartifactId>dependency><dependency>    <groupId>org.springframework.bootgroupId>    <artifactId>spring-boot-starter-testartifactId>    <scope>testscope>    <exclusions>        <exclusion>            <groupId>org.junit.vintagegroupId>            <artifactId>junit-vintage-engineartifactId>        exclusion>    exclusions>dependency>

第二步:导入相关依赖包和配置

1、需要导入的包有两个,一个是连接mysql数据库相关的包,另一个是springboot的模版解析引擎thymeleaf。

<dependency>    <groupId>org.springframework.bootgroupId>    <artifactId>spring-boot-starter-data-jpaartifactId>dependency><dependency>    <groupId>mysqlgroupId>    <artifactId>mysql-connector-javaartifactId>    <scope>runtimescope>dependency><dependency>    <groupId>org.springframework.bootgroupId>    <artifactId>spring-boot-starter-thymeleafartifactId>dependency>

2、在application.properties增加连接mysql数据库相关配置项,配置项包括登入mysql的用户名、密码、数据库名(study库)、驱动,如下:

# mysql连接相关的配置spring.datasource.username=rootspring.datasource.password=123456spring.datasource.url=jdbc:mysql://localhost:3306/studyspring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

第三步:编写对数据库的CURD操作

在编写CURD操作前,线了解一下项目当前的整体目录结构:

ec5a62c820a39c964eb2aaae161c0645.png

接下来我们主要是编写dao包中的内容。

1、首先在dao包中新建一个entity的包,并且包下新建两个类EmployeeDO和DepartmentDO,我们先来看一下这两个DO的关键代码:

@Entity注解标明此类是一个数据库实体类;

@Table标明对应的数据库的表名;

@lombok是为了简化类的getter和setter方法等;

这个类中定义了员工的各种信息,其中@Id注解标明是数据库主键,@GeneratedValue标明主键的生成策略,同时@DateTimeFormat定义日期格式

@Entity(name = "EmployeeDO")@Table(name = "employee")@lombok.Datapublic class EmployeeDO {    @Id    @GeneratedValue(strategy = GenerationType.IDENTITY)    private Long id;    private Long employeeId;    private String name;    private Integer gender;    @DateTimeFormat(pattern = "yyyy-MM-dd")    private Date birth;    private String email;    private Long departmentId;    private String describes;    @Override    public String toString() {        return String.format(            "employeeId:%d, name:%s, birth:%s, departmentId:%d, gender:%d, email:%s, describe:%s", employeeId,            name, birth.toString(), departmentId, gender, email, describes);    }}
@Entity(name = "DepartmentDO")@Table(name = "department")@lombok.Datapublic class DepartmentDO {    @Id    @GeneratedValue(strategy = GenerationType.AUTO)    private Long id;    private Long departmentId;    private String departmentName;}

这就定义好了代码实体与数据库表的对应关系。

2、接下来我们还需要在dao包中定义两个DAO类,来实现对数据库表的CURD操作,其中更新和删除操作需要标注Transactional注解,用于实现事务操作。

public interface EmployeeDAO extends JpaRepository<EmployeeDO, Long> {        EmployeeDO findEmployeeDOByEmployeeId(Long employeeId);    @Transactional    void deleteByEmployeeId(Long employeeId);    @Query("select max(e.employeeId) from EmployeeDO as e")    Long getMaxEmployeeId();    @Transactional    @Modifying    @Query("update EmployeeDO as e set e.name = ?2,e.gender=?3,e.birth=?4,e.email=?5,e.departmentId=?6,e.describes=?7 where e.employeeId=?1")    void updateEmployeeByEmployeeId(Long employeeId, String name, Integer gender, Date birth, String email, Long departmentId, String describes);}
public interface DepartmentDAO extends JpaRepository<DepartmentDO,Long> {    DepartmentDO findDepartmentDOByDepartmentId(Long departmentId);}

接下来我们看一下dao层的目录结构

57c2acfa89a5955525b9f9d8166935f0.png

第四步:编写Service层和Contoller层

1、service层相关,首先定义一个前端展示员工信息用的EmployeeDTO对象,关于DO、DTO、VO等概念,详见文章(https://blog.csdn.net/catoop/article/details/90053285)

@lombok.Datapublic class EmployeeDTO {    private Long employeeId;    private String name;    private Integer gender;    private Date birth;    private String email;    private DepartmentDO departmentDO;    private String describes;}
@Servicepublic class DepartmentService {    @Autowired    private DepartmentDAO departmentDAO;    public ListfindAllDepartment(){        return departmentDAO.findAll();    }}
@Servicepublic class EmployeeService {    @Autowired    private EmployeeDAO employeeDAO;    @Autowired    private DepartmentDAO departmentDAO;    public ListfindAllEmployees() {        List employeeDTOList = new ArrayList<>();        List employeeDOList = employeeDAO.findAll();        if (CollectionUtils.isEmpty(employeeDOList)) {            return new ArrayList<>();        }        for (EmployeeDO employeeDO : employeeDOList) {            EmployeeDTO employeeDTO = new EmployeeDTO();            BeanUtils.copyProperties(employeeDO, employeeDTO, "id", "departmentId");            DepartmentDO departmentDO = departmentDAO.findDepartmentDOByDepartmentId(employeeDO.getDepartmentId());            employeeDTO.setDepartmentDO(departmentDO);            employeeDTOList.add(employeeDTO);        }        return employeeDTOList;    }    public EmployeeDTO findEmployeeById(Long employeeId) {        EmployeeDTO employeeDTO = new EmployeeDTO();        EmployeeDO employeeDO = employeeDAO.findEmployeeDOByEmployeeId(employeeId);        BeanUtils.copyProperties(employeeDO, employeeDTO, "id", "departmentId");        DepartmentDO departmentDO = departmentDAO.findDepartmentDOByDepartmentId(employeeDO.getDepartmentId());        employeeDTO.setDepartmentDO(departmentDO);        return employeeDTO;    }    public void addEmployee(EmployeeDO employeeDO) {        if (employeeDO != null && employeeDO.getEmployeeId() == null) {            employeeDO.setEmployeeId(generateEmployeeId());        }        System.out.println(employeeDO.toString());        employeeDAO.save(employeeDO);    }    public void updateEmployee(EmployeeDO employeeDO) {        employeeDAO.updateEmployeeByEmployeeId(employeeDO.getEmployeeId(), employeeDO.getName(), employeeDO.getGender(),            employeeDO.getBirth(), employeeDO.getEmail(), employeeDO.getDepartmentId(), employeeDO.getDescribes());    }    public void deleteEmployee(Long employeeId) {        employeeDAO.deleteByEmployeeId(employeeId);    }    private Long generateEmployeeId() {        Long maxEmployeeId = employeeDAO.getMaxEmployeeId();        if (maxEmployeeId == null) {            maxEmployeeId = 0L;        }        return ++maxEmployeeId;    }}

关于代码内容,这里就不详细展开介绍了。service层的目录结构如下:

1f3af27eedd4623a5d56e4b23eaf462e.png

2、controller层相关,这里涉及前端页面,内容会稍微多一些

首先我们从Bootstrap官网(https://getbootstrap.com/docs/4.5/examples/)找一个合适的前端页面,定义一个登入页,命名为login.html并放在resources/templates目录下,同时在contoller包中定义一个LoginController类,定义get请求,获取请求登入页,定义登入请求提交登入用户名和密码。在了解代码前,我们先看一下登入页的样式

678808f5452e79bbae4269a50bc9db47.png

代码如下:

@Controllerpublic class LoginController {    @GetMapping("/login")    public String login(){        return "login";    }    @PostMapping("/user/login")    public String userLogin(@RequestParam("username") String username,        @RequestParam("password") String password,        Map error,        HttpSession session        ){        if(!StringUtils.isEmpty(username) && "123456".equals(password)){            session.setAttribute("loginUser",username);            return "dashboard";        }else{            error.put("msg","用户名密码错误");            return "login";        }    }}

可以看到get请求访问的login方法返回了login字符串,这个字符串会经过springboot模版引擎thymeleaf的解析,去项目的resources/templates目录下找login.html文件,我们看一下login.html中的关键代码:

    <form class="form-signin" th:action="@{/user/login}" method="post">      <img class="mb-4" src="/assets/brand/bootstrap-solid.svg" th:src="@{/assets/brand/bootstrap-solid.svg}" alt="" width="72" height="72">      <h1 class="h3 mb-3 font-weight-normal" text="请登入">请登入h1>      <p style="color:#ff0000" th:text="${msg}" th:if="${!#strings.isEmpty(msg)}">p>      <label class="sr-only" text="用户名">usernamelabel>      <input type="email" name="username" class="form-control" placeholder="用户名" required autofocus>      <label for="inputPassword" class="sr-only" text="密码">Passwordlabel>      <input type="password" id="inputPassword" name="password" class="form-control" placeholder="密码"  required>      <div class="checkbox mb-3">        <label>          <input type="checkbox" value="remeber"/> 记住我        label>      div>      <button class="btn btn-lg btn-primary btn-block" type="submit" th:text="登入">Sign inbutton>      <p class="mt-5 mb-3 text-muted">© 2017-2020p>    form>

定义了一个form表单,通过Post的方式(method="post")向user/login(th:action="@{/user/login}")路径发送请求,从而我们LoginController类中通过PostMapping注解接收并处理请求,最终跳转到了dashboard页面。关于login.html文件全部内容,这里就不做介绍了,接下来我们介绍dashboard页面,首先看一下页面样式

a1a8a00c454203b69209d4ce72cc6576.png

首先我用红框框出了顶部栏和侧边栏,这部分因为各个页面一致,所以做为公共元素被提取了出来,下面我们先看一下被提取出来的部分

<html lang="en" xmlns:th="http://www.thymeleaf.org"><head>    <meta charset="UTF-8">    <title>Titletitle>head><body>        <nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0 shadow" th:fragment="topbar">        <a class="navbar-brand col-md-3 col-lg-2 mr-0 px-3" href="#">[[${session.loginUser}]]a>        <button class="navbar-toggler position-absolute d-md-none collapsed" type="button" data-toggle="collapse"            data-target="#sidebarMenu" aria-controls="sidebarMenu" aria-expanded="false" aria-label="Toggle navigation">            <span class="navbar-toggler-icon">span>        button>        <input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">        <ul class="navbar-nav px-3">            <li class="nav-item text-nowrap">                <a class="nav-link" href="#">Sign outa>            li>        ul>    nav>        <nav id="sidebar" class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse">        <div class="sidebar-sticky pt-3">            <ul class="nav flex-column">                <li class="nav-item">                    <a class="nav-link active" th:class="${activeUri}=='dashboard.html' ? 'nav-link active' : 'nav-link'"                       href="#" th:href="@{/dashboard}">                        <span data-feather="home">span>                        主面板 <span class="sr-only">(current)span>                    a>                li>                <li class="nav-item">                    <a class="nav-link active" th:class="${activeUri}=='emps'?'nav-link active':'nav-link'"                       href="#" th:href="@{/emps}">                        <span data-feather="users">span>                        员工列表                    a>                li>            ul>        div>    nav>body>html>

首先topbar部分,从session中拿到了登入用户名,并展示([[${session.loginUser}]]),其次是侧边栏sidebar,通过nav-link控制是否高亮

dashboard.html中引入公共的topbar和sidebar的代码

    <div th:replace="commons/bar::topbar">div>  <div class="container-fluid">    <div class="row">                  <div th:replace="commons/bar::#sidebar(activeUri='dashboard.html')">div>    div>  div>html>

到此为止基本上登入页面的功能就算是实现了。可以看到点击侧边栏的员工列表,向后端发送了/emps的get请求,这个就到了员工列表页面,接下来我们就看一下员工列表页面的逻辑。

关于员工信息的处理,就到我们EmployeeController类登场了

@Controllerpublic class EmployeeController {    @Autowired    private EmployeeService employeeService;    @Autowired    private DepartmentService departmentService;    /**     * 获取员工列表     *     * @param model     * @return     */    @GetMapping("/emps")    public String findAllEmployees(Model model) {        List allEmployees = employeeService.findAllEmployees();        // 放在请求域中        model.addAttribute("emps", allEmployees);        // classpath:/templates/xxx.html        return "/emps/list";    }    @GetMapping("/emp")    public String addEmpPage(Model model) {        List allDepartment = departmentService.findAllDepartment();        model.addAttribute("depts", allDepartment);        return "/emps/add";    }    /**     * 添加员工     *     * @param employeeDO     * @return     */    @PostMapping("/emp")    public String addEmployee(EmployeeDO employeeDO) {        employeeService.addEmployee(employeeDO);        return "redirect:/emps";    }    /**     * 删除员工     *     * @param employeeId     * @return     */    @DeleteMapping("/emp/{employeeId}")    public String deleteEmployee(@PathVariable("employeeId") Long employeeId) {        employeeService.deleteEmployee(employeeId);        return "redirect:/emps";    }    @GetMapping("/emp/{employeeId}")    public String editEmployeePage(@PathVariable("employeeId") Long employeeId, Model model) {        EmployeeDTO employeeDTO = employeeService.findEmployeeById(employeeId);        List allDepartment = departmentService.findAllDepartment();        model.addAttribute("depts", allDepartment);        model.addAttribute("emp", employeeDTO);        return "/emps/add";    }    @PutMapping("/emp")    public String updateEmployee(EmployeeDO employeeDO){        employeeService.updateEmployee(employeeDO);        return "redirect:/emps";    }}

可以看到/emps请求直接查出了所有员工信息,并放入model中,方便页面获取,最后返回字符串/emps/list,这个会被thymeleaf模版引擎解析去找resources/templates/emps/list.html文件,接下来看一下list.html的关键代码

<body><div th:replace="commons/bar::topbar">div><div class="container-fluid">    <div class="row">                <div th:replace="commons/bar::#sidebar(activeUri='emps')">div>        <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4">            <h2>                <a class="btn btn-sm btn-success" th:href="@{/emp}">添加员工a>            h2>            <div class="table-responsive">                <table class="table table-striped table-sm">                    <thead>                    <tr>                        <th>employeeIdth>                        <th>nameth>                        <th>genderth>                        <th>departmentth>                        <th>birthth>                        <th>describeth>                        <th>operateth>                    tr>                    thead>                    <tbody>                    <tr th:each="emp:${emps}">                        <td th:text="${emp.employeeId}">td>                        <td>[[${emp.name}]]td>                        <td th:text="${emp.gender}==0?'男':'女'">td>                        <td th:text="${emp.departmentDO.departmentName}">td>                        <td th:text="${#dates.format(emp.birth,'yyyy-MM-dd HH:mm')}">td>                        <td th:text="${emp.describes}">td>                        <td>                            <a class="btn btn-sm btn-primary" th:href="@{/emp/}+${emp.employeeId}">edita>                            <button type="submit" th:attr="delete_uri=@{/emp/}+${emp.employeeId}" class="btn btn-danger deleteBtn">deletebutton>                        td>                    tr>                    tbody>                table>            div>        main>        <form id="deleteEmpForm" method="post">            <input type="hidden" name="_method" th:value="delete"/>        form>    div>div><script th:src="@{/assets/dist/js/jquery-3.5.1.js}">script><script src="../assets/dist/js/bootstrap.bundle.min.js" th:src="@{/assets/dist/js/bootstrap.bundle.min.js}">script><script src="https://cdnjs.cloudflare.com/ajax/libs/feather-icons/4.9.0/feather.min.js">script><script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js">script><script th:src="@{/assets/dist/js/dashboard.js}">script><script>    $('.deleteBtn').click(function(){        $("#deleteEmpForm").attr("action",$(this).attr("delete_uri")).submit();        return false;    });script>body>html>

首先是引入topbar和sidebar,接下来就是获取放入model中的员工信息了,获取方式为:<tr th:each="emp:${emps}">,然后依次展示每个员工信息,同时在删除操作时用js进行实现。

99fc33e75e8ae55f33f3e279f39c9aee.png

同时我们也在页面上看到了添加和修改员工按钮,接下来我们看一下这些的实现方式。

添加和修改员工分别向后端发送/emp和/emp/{employeeId}的get请求,这两个请求最终都返回了字符串/emps/add,接下来就看一下add.html文件

<body><div th:replace="commons/bar::topbar">div><div class="container-fluid">    <div class="row">                        <div th:replace="commons/bar::#sidebar(activeUri='dashboard.html')">div>        <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4">                        <form th:action="@{/emp}" method="post">                                                <input type="hidden" name="_method" value="put" th:if="${emp != null}">                <input type="hidden" name="employeeId" th:if="${emp != null}" th:value="${emp.employeeId}">                <div class="form-group">                    <label>Namelabel>                    <input name="name" type="text" class="form-control" placeholder="zhangsan" th:value="${emp} !=null ? ${emp.name}">                div>                <div class="form-group">                    <label>Emaillabel>                    <input name="email" type="email" class="form-control" placeholder="zhangsan@example.com" th:value="${emp} !=null ? ${emp.email}">                div>                <div class="form-group">                    <label>genderlabel>                    <div class="form-check form-check-inline">                        <input class="form-check-input" type="radio" name="gender" value="1" th:checked="${emp} !=null ? ${emp.gender==1}">                        <label class="form-check-label">女label>                    div>                    <div class="form-check form-check-inline">                        <input class="form-check-input" type="radio" name="gender" value="0" th:checked="${emp} !=null ? ${emp.gender==0}">                        <label class="form-check-label">男label>                    div>                div>                <div class="form-group">                    <label>departmentlabel>                    <select class="form-control" name="departmentId">                                                <option th:selected="${emp} !=null ? ${dept.departmentId=emp.departmentDO.departmentId}" th:value="${dept.departmentId}" th:each="dept:${depts}" th:text="${dept.departmentName}">1option>                    select>                div>                <div class="form-group">                    <label>birthlabel>                    <input type="text" class="form-control" placeholder="2020-01-01" name="birth" th:value="${emp} !=null ? ${#dates.format(emp.birth,'yyyy-MM-dd hh:mm:ss')}">input>                div>                <div class="form-group">                    <label>describelabel>                    <textarea class="form-control" id="describes" name="describes" rows="3">textarea>                div>                <button type="submit" class="btn btn-primary" th:text="${emp} !=null ? '修改' : '添加'">添加button>            form>        main>    div>div>body>

也是首先引入topbar和sidebar,新增和修改用的同一个页面,是通过model中有没有emp参数来判断的,有emp信息的为修改,没有的为新增。本次的介绍就到这里吧,详细的代码见github,链接:https://github.com/bestlei/employee-management

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值