SpringBoot项目练习

news2024/11/26 17:48:57

项目名称:旅游网站后台管理

一:项目简介

旅游网站后台管理,包括如下

用户:

旅游线路:

线路图片:

线路分类:

旅行社:

后台技术:

springboot、mybatis、mybatis plus

前台:

bootstrap、jquery、thymeleaf、fileinput插件

数据库:

mysql


数据库设计:

表结构:

二:创建项目

<?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.lxs.travel</groupId>
    <artifactId>travel-springboot-mp</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
        <relativePath/> <!-- 依赖spring-boot-starter-parent构件时,从本地仓库-> 远程仓库获取,不从本地目录获取 -->
    </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-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <!--mybatis plus-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.3.2</version>
    </dependency>
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper</artifactId>
        <version>5.1.11</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.46</version>
    </dependency>
    <!--fileupload-->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.0.RELEASE</version>
            </plugin>
        </plugins>
    </build>
</project>

application.yml:

server:
  port: 80
  servlet:
    context-path: /  #项目的上下文路径
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/travel
    username: root
    password: linda198721
    driver-class-name: com.mysql.jdbc.Driver
    hikari:
      idle-timeout: 60000
      maximum-pool-size: 30
      minimum-idle: 10
  thymeleaf:
    cache: false
#mybatis plus配置
mybatis-plus:
  mapper-locations: classpath:/mybatis/*.xml #加载映射文件
  type-aliases-package: com.lxs.travel.domain #别名搜索包
  configuration:
    lazy-loading-enabled: true #打开懒加载
    aggressive-lazy-loading: false #关闭积极加载

启动器:

package com.lxs.travel;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

整合mybatis plus:

package com.lxs.travel.config;

import com.github.pagehelper.PageInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.lxs.travel.dao")
public class MybatisPlusConfig {

    @Bean
    public PageInterceptor pageInterceptor(){
        return new PageInterceptor();
    }

}

三:用户管理

实体类:

Lombok能以简单的注解形式来简化java代码,提高开发人员的开发效率
使用lomhok简化实体类开发,具体lomhok语法和安装参考资料lomhok入门.html文档
package com.lxs.travel.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

@Data
@TableName("tab_user")
public class User implements Serializable {
    @TableId(type = IdType.AUTO)
    private Integer uid;
    private String username;
    private String password;
    private String name;
    private Date birthday;
    private String sex;
    private String telephone;
    private String email;
    private String status;
    private String code;
    private Boolean isadmin;
}

dao:

package com.lxs.travel.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lxs.travel.domain.User;

public interface UserDao extends BaseMapper<User> {

}

注意:这里使用mybatis plus内置方法,没有映射文件

service:

package com.lxs.travel.service;

import com.github.pagehelper.PageInfo;
import com.lxs.travel.domain.User;

import java.util.List;

public interface UserService {
    /**
     * 分页查询
     * @param conditioin 查询条件
     * @return
     */
    public PageInfo<User> findPage(User conditioin, int pageNum, int pageSize);

    /**
     * 查询
     * @param conditioin 查询条件
     * @return
     */
    public List<User> find(User conditioin);

    /**
     * 添加
     * @param user
     * @return
     */
    public int add(User user);

    /**
     * 根据ID查询用户
     * @param id
     * @return
     */
    public User findById(Integer id);

    /**
     * 修改
     * @param user
     * @return
     */
    public int update(User user);

    /**
     * 删除
     * * @param id
     * * @return
     * */
    public int delete(Integer id);
}

实现类:

package com.lxs.travel.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.lxs.travel.dao.UserDao;
import com.lxs.travel.domain.User;
import com.lxs.travel.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Override
    public PageInfo<User> findPage(User conditioin, int pageNum, int pageSize) {
        return PageHelper.startPage(pageNum,pageSize).doSelectPageInfo(()->{
           userDao.selectList(Wrappers.<User>query());
        });
    }

    @Override
    public List<User> find(User conditioin) {
        return userDao.selectList(Wrappers.<User>query());
    }

    @Override
    public int add(User user) {
        return userDao.insert(user);
    }

    @Override
    public User findById(Integer id) {
        return userDao.selectById(id);
    }

    @Override
    public int update(User user) {
        return userDao.updateById(user);
    }

    @Override
    public int delete(Integer id) {
        return userDao.deleteById(id);
    }
}

注意:分页方法采用的lambda表达式的写法

测试:

package com.lxs.travel.service.impl;

import com.github.pagehelper.PageInfo;
import com.lxs.travel.domain.User;
import com.lxs.travel.service.UserService;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Arrays;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceImplTest extends TestCase {

    @Autowired
    private UserService userService;

    @Test
    public void testFindPage() {
        User u = new User();
        PageInfo<User> page = userService.findPage(u, 1, 10);
        page.getList().forEach(System.out :: println);
        System.out.println("总行数=" + page.getTotal());
        System.out.println("当前页=" + page.getPageNum());
        System.out.println("每页行数=" + page.getPageSize());
        System.out.println("总页数=" + page.getPages());
        System.out.println("起始行数=" + page.getStartRow());
        System.out.println("是第一页=" + page.isIsFirstPage());
        System.out.println("是最后页=" + page.isIsLastPage());
        System.out.println("还有下一页=" + page.isHasNextPage());
        System.out.println("还有上一页=" + page.isHasPreviousPage());
        System.out.println("页码列表" + Arrays.toString(page.getNavigatepageNums()));
    }
}

controller:

package com.lxs.travel.controller;

import com.github.pagehelper.PageInfo;
import com.lxs.travel.domain.User;
import com.lxs.travel.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/admin/user")
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 分页查询
     */
    @RequestMapping("/page")
    public String page(User user,
                       @RequestParam(defaultValue = "1") Integer pageNum,
                       @RequestParam(defaultValue = "10") Integer pageSize,
                       Model model){
        PageInfo<User> page = userService.findPage(user, pageNum, pageSize);
        model.addAttribute("page",page);
        return "/user/list";
    }

    /**
     * 跳转到加载页面
     */
    @RequestMapping("/toAdd")
    public String toAdd(){
        return "/user/add";
    }

    /**
     * 添加
     */
    @RequestMapping("/doAdd")
    public String doAdd(User user){
        userService.add(user);
        return "redirect:/admin/user/page";
    }

    /**
     * 跳转到修改页面
     */
    @RequestMapping("/toupdate/{id}")
    public String toUpdate(@PathVariable("id") Integer id,Model model){
        User user = userService.findById(id);
        model.addAttribute("user",user);
        return "/user/update";
    }

    /**
     * 修改
     */
    @RequestMapping("/doupdate")
    public String doUpdate(User user){
        userService.update(user);
        return "redirect:/admin/user/page";
    }

    /**
     * 删除
     */
    @RequestMapping("/delete/{id}")
    public String delete(@PathVariable("id") Integer id){
        userService.delete(id);
        return "redirect:/admin/user/page";
    }

    /**
     * 批量删除
     */
    @RequestMapping("/delete")
    public String batchDelete(@RequestParam("ids") Integer[] ids){
        for (Integer id : ids) {
            userService.delete(id);
        }
        return "redirect:/admin/user/page";
    }
}

页面:

前端技术栈 bootstrap,jquery,ace, fileinput插件

这里我们直接拷贝index.html,header.html,和left.html

list.html:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:javascript="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
    <meta charset="utf-8"/>
    <title>用户管理</title>

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"/>

    <!-- bootstrap & fontawesome -->
    <link rel="stylesheet" href="/assets/css/bootstrap.min.css"/>
    <link rel="stylesheet" href="/assets/font-awesome/4.5.0/css/font-awesome.min.css"/>

    <!-- page specific plugin styles -->

    <!-- text fonts -->
    <link rel="stylesheet" href="/assets/css/fonts.googleapis.com.css"/>

    <!-- ace styles -->
    <link rel="stylesheet" href="/assets/css/ace.min.css" class="ace-main-stylesheet" id="main-ace-style"/>

    <!--[if lte IE 9]>
    <link rel="stylesheet" href="/assets/css/ace-part2.min.css" class="ace-main-stylesheet"/>
    <![endif]-->
    <link rel="stylesheet" href="/assets/css/ace-skins.min.css"/>
    <link rel="stylesheet" href="/assets/css/ace-rtl.min.css"/>

    <!--[if lte IE 9]>
    <link rel="stylesheet" href="/assets/css/ace-ie.min.css"/>
    <![endif]-->

    <!-- inline styles related to this page -->

    <!-- ace settings handler -->
    <script src="/assets/js/ace-extra.min.js"></script>

    <!-- HTML5shiv and Respond.js for IE8 to support HTML5 elements and media queries -->

    <!--[if lte IE 8]>
    <script src="/assets/js/html5shiv.min.js"></script>
    <script src="/assets/js/respond.min.js"></script>
    <![endif]-->

    <!--[if !IE]> -->
    <script src="/assets/js/jquery-2.1.4.min.js"></script>

    <!-- <![endif]-->

    <!--[if IE]>
    <script src="/assets/js/jquery-1.11.3.min.js"></script>
    <![endif]-->
    <script src="/assets/js/bootstrap.min.js"></script>

    <!-- page specific plugin scripts -->
    <script src="/assets/js/jquery.dataTables.min.js"></script>
    <script src="/assets/js/jquery.dataTables.bootstrap.min.js"></script>
    <script src="/assets/js/dataTables.buttons.min.js"></script>
    <script src="/assets/js/buttons.flash.min.js"></script>
    <script src="/assets/js/buttons.html5.min.js"></script>
    <script src="/assets/js/buttons.print.min.js"></script>
    <script src="/assets/js/buttons.colVis.min.js"></script>
    <script src="/assets/js/dataTables.select.min.js"></script>

    <!-- ace scripts -->
    <script src="/assets/js/ace-elements.min.js"></script>
    <script src="/assets/js/ace.min.js"></script>

    <!-- TODO 页面删除js -->
    <script>
        $(function (){
            $("#checkAll").change(function (){
               $(":checkbox[name='ids']").prop("checked",$(this).prop("checked"));
            });
            $("#btnDelete").click(function (){
                if($(":checked[name='ids']").length > 0){
                    $("#df").submit();
                }else {
                    alert("请选择要删除的记录");
                }
            })
        })
    </script>

</head>

<body class="no-skin">

<div th:replace="header :: navbar"></div>

<div class="main-container ace-save-state" id="main-container">
    <script type="text/javascript">
        try {
            ace.settings.loadState('main-container')
        } catch (e) {
        }
    </script>

    <div th:replace="left :: sidebar"></div>

    <div class="main-content">
        <div class="main-content-inner">
            <div class="breadcrumbs ace-save-state" id="breadcrumbs">
                <ul class="breadcrumb">
                    <li>
                        <i class="ace-icon fa fa-home home-icon"></i>
                        <a href="#">首页</a>
                    </li>
                    <li>
                        <a href="#">用户</a>
                    </li>
                    <li class="active">用户管理</li>
                </ul><!-- /.breadcrumb -->

            </div>

            <div class="page-content">

                <div style="float: left; padding: 10px;">
                    <form class="form-inline" id="qf" action="/admin/user/page" method="post">
                        <input type="hidden" name="pageNum" id="pageNum" th:value="${page.pageNum}">
                        <input type="hidden" name="pageSize" id="pageSize" th:value="${page.pageSize}">
                        <div class="form-group">
                            <label for="name">姓名</label>
                            <input type="text" name="name" class="form-control" id="name" th:value="${param.name}">
                        </div>
                        <div class="form-group">
                            <label for="email">邮箱</label>
                            <input type="text" name="email" class="form-control" id="email" th:value="${param.email}">
                        </div>
                        <button type="submit" class="btn btn-sm btn-default">查询</button>
                        <button type="button" class="btn btn-sm btn-default" onclick="location.href='/admin/user/toAdd'">添加</button>
                        <button type="button" class="btn btn-sm btn-default" id="btnDelete">删除</button>
                    </form>
                </div>


                <!--TODO 删除表单-->
                <form action="/admin/user/delete" method="post" id="df">
                <table id="simple-table" class="table  table-bordered table-hover">
                    <thead>
                    <tr>
                        <th><input type="checkbox" id="checkAll"></th>
                        <th>姓名</th>
                        <th>性别</th>
                        <th>出生日期</th>
                        <th>电话</th>
                        <th>邮箱</th>
                        <th>操作</th>
                    </tr>
                    </thead>
                    <!-- TODO 回显数据 -->
                    </thead>
                    <tbody>
                    <tr th:each="u, status : ${page.list}" th:style="${status.even} ?'background-color: grey'">
                        <td><input type="checkbox" name="ids" th:value="${u.uid}"></td>
                        <td th:text="${u.name}"></td>
                        <td th:text="${u.sex}"></td>
                        <td th:text="${#dates.format(u.birthday, 'yyyy-MM-dd')}"></td>
                        <td th:text="${u.telephone}"></td>
                        <td th:text="${u.email}"></td>
                        <td>
                            <div class="hidden-sm hidden-xs btn-group">
                                <a class="btn btn-xs btn-info"
                                   th:href="|/admin/user/toupdate/${u.uid}|" >
                                    <i class="ace-icon fa fa-pencil bigger-120"></i>
                                </a>
                                <a class="btn btn-xs btn-info"
                                   th:href="|/admin/user/delete/${u.uid}|">
                                    <i class="ace-icon fa fa-trash-o bigger-120"></i>
                                </a>
                            </div>
                        </td>
                    </tr>
                    </tbody>
                </table>
                </form>

                <!-- TODO 回显数据 -->
                <div>
                    <nav aria-label="Page navigation">
                        <ul class="pagination">
                            <li id="first">
                                <a href="javascript:void(0);">
                                    <span aria-hidden="true">首页</span>
                                </a>
                            </li>
                            <li id="prev">
                                <a href="javascript:void(0);" aria-label="Previous">
                                    <span aria-hidden="true">上一页</span>
                                </a>
                            </li>
                            <li name="pageNum" th:each="i : ${page.navigatepageNums}" th:class="${i==page.pageNum} ? 'active'">
                            <a href="javascript:void(0);" th:text="${i}" ></a>
                            </li>

                            <li id="next">
                                <a href="javascript:void(0);" aria-label="Next">
                                    <span aria-hidden="true">下一页</span>
                                </a>
                            </li>

                            <li id="last">
                                <a href="javascript:void(0);">
                                    <span aria-hidden="true">末页</span>
                                </a>
                            </li>

                            <span style="font-size: 20px;margin-left: 5px;"
                                  th:text="|共条${page.total} 记录,共${page.pages}页, 每页${page.pageSize}行数|">
                                            </span>
                            <select id="setRows">
                                <option value="5" >5</option>
                                <option value="10" >10</option>
                                <option value="20" >20</option>
                                <option value="30" >30</option>
                            </select>

                        </ul>
                    </nav>
                </div>

                <!-- TODO 分页JS -->
                <script th:inline="javascript">
                    //得到初始化变量
                    var pageNum=[[${page.pageNum}]]; //当前页
                    var pages=[[${page.pages}]]; //总页数
                    var hasNextPage=[[${page.hasNextPage}]]; //true 还有下一页
                    var hasPrevious=[[${page.hasPreviousPage}]]; //还有上一页

                    //判断按钮状态
                    if(!hasPrevious){
                        $("#prev").addClass("disabled");
                        $("#first").addClass("disabled");
                    }
                    if(!hasNextPage){
                        $("#next").addClass("disabled");
                        $("#last").addClass("disabled");
                    }

                    //设置按钮的监听事件
                    $("#first").click(function (){
                        if(!$("#first").hasClass("disabled")){
                            $("#pageNum").val(1);
                            $("#qf").submit();
                        }
                    });
                    $("#prev").click(function (){
                        if(!$("#prev").hasClass("disabled")){
                            $("#pageNum").val(pageNum-1);
                            $("#qf").submit();
                        }
                    })
                    $("#next").click(function (){
                        if(!$("#next").hasClass("disabled")){
                            $("#pageNum").val(pageNum+1);
                            $("#qf").submit();
                        }
                    })
                    $("#last").click(function (){
                        if(!$("#last").hasClass("disabled")){
                            $("#pageNum").val(pages);
                            $("#qf").submit();
                        }
                    })

                    //页码分页
                    $("li[name='pageNum']").click(function (){
                       if(!$(this).hasClass("active")){
                           $("#pageNum").val($(this).children("a").html());
                           $("#qf").submit();
                       }
                    });

                    //设置每页行数
                    $("#setRows").change(function (){
                       $("#pageSize").val($(this).val());
                       $("#pageNum").val(1);
                       $("#qf").submit();
                    });

                </script>
            </div><!-- /.page-content -->
        </div>
    </div><!-- /.main-content -->

</div><!-- /.main-container -->

</body>
</html>

add.html:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta charset="utf-8" />
    <title>用户管理</title>

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />

    <!-- bootstrap & fontawesome -->
    <link rel="stylesheet" href="/assets/css/bootstrap.min.css" />
    <link rel="stylesheet" href="/assets/font-awesome/4.5.0/css/font-awesome.min.css" />

    <!-- page specific plugin styles -->

    <!-- text fonts -->
    <link rel="stylesheet" href="/assets/css/fonts.googleapis.com.css" />

    <!-- ace styles -->
    <link rel="stylesheet" href="/assets/css/ace.min.css" class="ace-main-stylesheet" id="main-ace-style" />

    <!--[if lte IE 9]>
    <link rel="stylesheet" href="/assets/css/ace-part2.min.css" class="ace-main-stylesheet" />
    <![endif]-->
    <link rel="stylesheet" href="/assets/css/ace-skins.min.css" />
    <link rel="stylesheet" href="/assets/css/ace-rtl.min.css" />

    <!--[if lte IE 9]>
    <link rel="stylesheet" href="/assets/css/ace-ie.min.css" />
    <![endif]-->

    <!-- inline styles related to this page -->

    <!-- ace settings handler -->
    <script src="/assets/js/ace-extra.min.js"></script>

    <!-- HTML5shiv and Respond.js for IE8 to support HTML5 elements and media queries -->

    <!--[if lte IE 8]>
    <script src="/assets/js/html5shiv.min.js"></script>
    <script src="/assets/js/respond.min.js"></script>
    <![endif]-->

    <!--[if !IE]> -->
    <script src="/assets/js/jquery-2.1.4.min.js"></script>

    <!-- <![endif]-->

    <!--[if IE]>
    <script src="/assets/js/jquery-1.11.3.min.js"></script>
    <![endif]-->
    <script src="/assets/js/bootstrap.min.js"></script>

    <!-- page specific plugin scripts -->
    <script src="/assets/js/jquery.dataTables.min.js"></script>
    <script src="/assets/js/jquery.dataTables.bootstrap.min.js"></script>
    <script src="/assets/js/dataTables.buttons.min.js"></script>
    <script src="/assets/js/buttons.flash.min.js"></script>
    <script src="/assets/js/buttons.html5.min.js"></script>
    <script src="/assets/js/buttons.print.min.js"></script>
    <script src="/assets/js/buttons.colVis.min.js"></script>
    <script src="/assets/js/dataTables.select.min.js"></script>

    <!-- ace scripts -->
    <script src="/assets/js/ace-elements.min.js"></script>
    <script src="/assets/js/ace.min.js"></script>

    <script language="javascript" type="text/javascript" src="/js/My97DatePicker/WdatePicker.js"></script>

</head>

<body class="no-skin">

<div th:replace="header :: navbar"></div>

<div class="main-container ace-save-state" id="main-container">
    <script type="text/javascript">
        try{ace.settings.loadState('main-container')}catch(e){}
    </script>

    <div th:replace="left :: sidebar"></div>

    <div class="main-content">
        <div class="main-content-inner">
            <div class="breadcrumbs ace-save-state" id="breadcrumbs">
                <ul class="breadcrumb">
                    <li>
                        <i class="ace-icon fa fa-home home-icon"></i>
                        <a href="#">首页</a>
                    </li>

                    <li>
                        <a href="#">用户</a>
                    </li>
                    <li class="active">用户管理</li>
                </ul><!-- /.breadcrumb -->

            </div>

            <div class="page-content">

                <form action="/admin/user/doAdd" method="post">
                    <div class="form-group">
                        <label for="name">姓名:</label>
                        <input type="text" class="form-control" id="name" name="name" placeholder="请输入姓名">
                    </div>

                    <div class="form-group">
                        <label>性别:</label>
                        <input type="radio" name="sex" value="男" checked="checked"/>男
                        <input type="radio" name="sex" value="女"/>女
                    </div>

                    <div class="form-group">
                        <label for="birthday">生日:</label>
                        <input type="text" class="form-control" id="birthday" name="birthday" placeholder="请输入生日" onClick="WdatePicker({el:this,dateFmt:'yyyy-MM-dd'})">
                    </div>

                    <div class="form-group">
                        <label for="telephone">电话:</label>
                        <input type="text" class="form-control" name="telephone" id="telephone" placeholder="请输入电话"/>
                    </div>

                    <div class="form-group">
                        <label for="email">Email:</label>
                        <input type="text" class="form-control" name="email" id="email" placeholder="请输入邮箱地址"/>
                    </div>

                    <div class="form-group">
                        <label for="username">登录名</label>
                        <input type="text" class="form-control" name="username" id="username" placeholder="请输入登录名"/>
                    </div>

                    <div class="form-group">
                        <label for="password">密码</label>
                        <input type="text" class="form-control" name="password" id="password" placeholder="请输入密码"/>
                    </div>

                    <div class="form-group" style="text-align: center">
                        <input class="btn btn-primary" type="submit" value="提交" />
                        <input class="btn btn-default" type="reset" value="重置" />
                        <input class="btn btn-default" type="button" value="返回" />
                    </div>
                </form>

            </div><!-- /.page-content -->
        </div>
    </div><!-- /.main-content -->

</div><!-- /.main-container -->

</body>
</html>

update.html:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta charset="utf-8" />
    <title>用户管理</title>

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />

    <!-- bootstrap & fontawesome -->
    <link rel="stylesheet" href="/assets/css/bootstrap.min.css" />
    <link rel="stylesheet" href="/assets/font-awesome/4.5.0/css/font-awesome.min.css" />

    <!-- page specific plugin styles -->

    <!-- text fonts -->
    <link rel="stylesheet" href="/assets/css/fonts.googleapis.com.css" />

    <!-- ace styles -->
    <link rel="stylesheet" href="/assets/css/ace.min.css" class="ace-main-stylesheet" id="main-ace-style" />

    <!--[if lte IE 9]>
    <link rel="stylesheet" href="/assets/css/ace-part2.min.css" class="ace-main-stylesheet" />
    <![endif]-->
    <link rel="stylesheet" href="/assets/css/ace-skins.min.css" />
    <link rel="stylesheet" href="/assets/css/ace-rtl.min.css" />

    <!--[if lte IE 9]>
    <link rel="stylesheet" href="/assets/css/ace-ie.min.css" />
    <![endif]-->

    <!-- inline styles related to this page -->

    <!-- ace settings handler -->
    <script src="/assets/js/ace-extra.min.js"></script>

    <!-- HTML5shiv and Respond.js for IE8 to support HTML5 elements and media queries -->

    <!--[if lte IE 8]>
    <script src="/assets/js/html5shiv.min.js"></script>
    <script src="/assets/js/respond.min.js"></script>
    <![endif]-->

    <!--[if !IE]> -->
    <script src="/assets/js/jquery-2.1.4.min.js"></script>

    <!-- <![endif]-->

    <!--[if IE]>
    <script src="/assets/js/jquery-1.11.3.min.js"></script>
    <![endif]-->
    <script src="/assets/js/bootstrap.min.js"></script>

    <!-- page specific plugin scripts -->
    <script src="/assets/js/jquery.dataTables.min.js"></script>
    <script src="/assets/js/jquery.dataTables.bootstrap.min.js"></script>
    <script src="/assets/js/dataTables.buttons.min.js"></script>
    <script src="/assets/js/buttons.flash.min.js"></script>
    <script src="/assets/js/buttons.html5.min.js"></script>
    <script src="/assets/js/buttons.print.min.js"></script>
    <script src="/assets/js/buttons.colVis.min.js"></script>
    <script src="/assets/js/dataTables.select.min.js"></script>

    <!-- ace scripts -->
    <script src="/assets/js/ace-elements.min.js"></script>
    <script src="/assets/js/ace.min.js"></script>

    <script language="javascript" type="text/javascript" src="/js/My97DatePicker/WdatePicker.js"></script>


</head>

<body class="no-skin">

<div th:replace="header :: navbar"></div>

<div class="main-container ace-save-state" id="main-container">
    <script type="text/javascript">
        try{ace.settings.loadState('main-container')}catch(e){}
    </script>

    <div th:replace="left :: sidebar"></div>

    <div class="main-content">
        <div class="main-content-inner">
            <div class="breadcrumbs ace-save-state" id="breadcrumbs">
                <ul class="breadcrumb">
                    <li>
                        <i class="ace-icon fa fa-home home-icon"></i>
                        <a href="#">首页</a>
                    </li>
                    <li>
                        <a href="#">用户</a>
                    </li>
                    <li class="active">用户管理</li>
                </ul><!-- /.breadcrumb -->

            </div>

            <div class="page-content">

                <!-- TODO 回显数据 -->
                <form action="/admin/user/doupdate" method="post" th:object="${user}" >
                    <input type="hidden" name="uid" >
                    <div class="form-group">
                        <label for="name">姓名:</label>
                        <!-- TODO 回显姓名  --> 
                        <input type="text" class="form-control" id="name" name="name" placeholder="请输入姓名" th:value="*{name}" >
                    </div>

                    <div class="form-group">
                        <label>性别:</label>
                        <input type="radio" name="sex" value="男" th:checked="'男' == *{sex}" />男
                        <input type="radio" name="sex" value="女" th:checked="'女' == *{sex}" />女
                    </div>


                    <div class="form-group">
                        <label for="birthday">生日:</label>
                        <input type="text" class="form-control" id="birthday" name="birthday" placeholder="请输入生日" onClick="WdatePicker({el:this,dateFmt:'yyyy-MM-dd'})" th:value="*{birthday}">
                    </div>


                    <div class="form-group">
                        <label for="telephone">电话:</label>
                        <input type="text" class="form-control" name="telephone" id="telephone" placeholder="请输入电话" th:value="*{telephone}"/>
                    </div>

                    <div class="form-group">
                        <label for="email">Email:</label>
                        <input type="text" class="form-control" name="email" id="email" placeholder="请输入邮箱地址" th:value="*{email}"/>
                    </div>

                    <div class="form-group">
                        <label for="username">登录名</label>
                        <input type="text" class="form-control" name="username" id="username" placeholder="请输入登录名" th:value="*{username}"/>
                    </div>

                    <div class="form-group">
                        <label for="password">密码</label>
                        <input type="text" class="form-control" name="password" id="password" placeholder="请输入密码" th:value="*{password}"/>
                    </div>


                    <div class="form-group" style="text-align: center">
                        <input class="btn btn-primary" type="submit" value="提交" />
                        <input class="btn btn-default" type="reset" value="重置" />
                        <input class="btn btn-default" type="button" value="返回" />
                    </div>
                </form>

            </div><!-- /.page-content -->

        </div>
    </div><!-- /.main-content -->

</div><!-- /.main-container -->

</body>
</html>

多选删除:

    /**
     * 批量删除
     */
    @RequestMapping("/delete")
    public String batchDelete(@RequestParam("ids") Integer[] ids){
        for (Integer id : ids) {
            userService.delete(id);
        }
        return "redirect:/admin/user/page";
    }

页面

<!-- TODO 页面删除js -->
    <script>
        $(function (){
            $("#checkAll").change(function (){
               $(":checkbox[name='ids']").prop("checked",$(this).prop("checked"));
            });
            $("#btnDelete").click(function (){
                if($(":checked[name='ids']").length > 0){
                    $("#df").submit();
                }else {
                    alert("请选择要删除的记录");
                }
            })
        })
    </script>

注入在springmvc中配置日期转换器

package com.lxs.travel.utils;

import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Component
public class DateConverterConfig implements Converter<String, Date> {
    private static final List<String> formarts = new ArrayList<>(4);
    static{
        formarts.add("yyyy-MM");
        formarts.add("yyyy-MM-dd");
        formarts.add("yyyy-MM-dd hh:mm");
        formarts.add("yyyy-MM-dd hh:mm:ss");
    }
    @Override
    public Date convert(String source) {
        String value = source.trim();
        if ("".equals(value)) {
            return null;
        }
        if(source.matches("^\\d{4}-\\d{1,2}$")){
            return parseDate(source, formarts.get(0));
        }else if(source.matches("^\\d{4}-\\d{1,2}-\\d{1,2}$")){
            return parseDate(source, formarts.get(1));
        }else if(source.matches("^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}$")){
            return parseDate(source, formarts.get(2));
        }else if(source.matches("^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}:\\d{1,2}$")){
            return parseDate(source, formarts.get(3));
        }else {
            throw new IllegalArgumentException("Invalid boolean value '" + source + "'");
        }
    }
    /**
     * 格式化日期
     * @param dateStr String 字符型日期
     * @param format String 格式
     * @return Date 日期
     */
    public Date parseDate(String dateStr, String format) {
        Date date=null;
        try {
            DateFormat dateFormat = new SimpleDateFormat(format);
            date = dateFormat.parse(dateStr);
        } catch (Exception e) {
        }
        return date;
    }
}

四:旅游公司

参考用户管理CRUD操作,具体代码和用户管理相似

实体类

package com.lxs.travel.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;

@Data
@TableName("tab_seller")
public class Seller implements Serializable {
    @TableId(type = IdType.AUTO)
    private Integer sid;//商家id
    private String sname;//商家名称
    private String consphone;//商家电话
    private String address;//商家地址
}

dao

package com.lxs.travel.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lxs.travel.domain.Seller;
import org.apache.ibatis.annotations.Select;

public interface SellerDao extends BaseMapper<Seller> {

    @Select("SELECT * FROM tab_seller WHERE sid=#{id}")
    public Seller findById(Integer id);

}

service

接口

package com.lxs.travel.service;

import com.github.pagehelper.PageInfo;
import com.lxs.travel.domain.Seller;

import java.util.List;

public interface SellerService {
    /**
     * 分页查询
     * @param conditioin 查询条件
     * @return
     */
    public PageInfo<Seller> findPage(Seller conditioin, int pageNum, int pageSize);
    /**
     * 查询
     * @param conditioin 查询条件
     * @return
     */
    public List<Seller> find(Seller conditioin);
    /**
     * 添加
     * @param seller
     * @return
     */
    public int add(Seller seller);
    /**
     * 根据ID查询用户
     * @param id
     * @return
     */
    public Seller findById(Integer id);
    /**
     * 修改
     * @param seller
     * @return
     */
    public int update(Seller seller);
    /**
     * 删除
     * @param id
     * @return
     */
    public int delete(Integer id);
}

实现类

package com.lxs.travel.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.lxs.travel.dao.SellerDao;
import com.lxs.travel.domain.Seller;
import com.lxs.travel.service.SellerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class SellerServiceImpl implements SellerService {
    @Autowired
    private SellerDao sellerDao;
    @Override
    public PageInfo<Seller> findPage(Seller conditioin, int pageNum, int pageSize) {
        return PageHelper.startPage(pageNum, pageSize).doSelectPageInfo(() -> {
            sellerDao.selectList(new QueryWrapper<Seller>());
        });
    }
    @Override
    public List<Seller> find(Seller condition) {
        return sellerDao.selectList(Wrappers.query());
    }
    @Override
    public int add(Seller seller) {
        return sellerDao.insert(seller);
    }
    @Override
    public Seller findById(Integer id) {
        return sellerDao.selectById(id);
    }
    @Override
    public int update(Seller seller) {
        return sellerDao.updateById(seller);
    }
    @Override
    public int delete(Integer id) {
        return sellerDao.deleteById(id);
    }
}

controller

package com.lxs.travel.controller;

import com.github.pagehelper.PageInfo;
import com.lxs.travel.domain.Seller;
import com.lxs.travel.service.SellerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/admin/seller")
public class SellerController {
    @Autowired
    private SellerService sellerService;
    @RequestMapping("/page")
    public String page(
            Seller seller,
            @RequestParam(defaultValue = "1") Integer pageNum,
            @RequestParam(defaultValue = "10") Integer pageSize,
            Model model) {
        PageInfo<Seller> page = sellerService.findPage(seller, pageNum, pageSize);
        model.addAttribute("page", page);
        return "/seller/list";
    }
    @RequestMapping("/toadd")
    public String toAdd() {
        return "seller/add";
    }
    @RequestMapping("/doadd")
    public String doAdd(Seller seller) {
        sellerService.add(seller);
        return "redirect:/admin/seller/page";
    }
    @RequestMapping("/toupdate")
    public String toUpdate(Integer id, Model model) {
        Seller seller = sellerService.findById(id);
        model.addAttribute("seller", seller);
        return "/seller/update";
    }
    @RequestMapping("/doupdate")
    public String doUpdate(Seller seller) {
        sellerService.update(seller);
        return "redirect:/admin/seller/page";
    }
    @RequestMapping("/delete")
    public String delete(Integer id) {
        sellerService.delete(id);
        return "redirect:/admin/seller/page";
    }
}

页面

页面代码和用户crud基本一致,直接从素材拷贝即可

五:线路分类

实体类

package com.lxs.travel.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;

@Data
@TableName("tab_category")
public class Category implements Serializable {
    @TableId(type = IdType.AUTO)
    private Integer cid;//分类id
    private String cname;//分类名称
}

dao

package com.lxs.travel.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lxs.travel.domain.Category;
import org.apache.ibatis.annotations.Select;

public interface CategoryDao extends BaseMapper<Category> {

    @Select("SELECT cname,cid FROM tab_category WHERE cid=#{id}")
    public Category findById(Integer id);

}

service

接口

package com.lxs.travel.service;

import com.lxs.travel.domain.Category;

import java.util.List;

public interface CategoryService {
    public List<Category> find();
    /**
     * 添加
     * @param category
     * @return
     */
    public int add(Category category);
    /**
     * 根据ID查询
     * @param id
     * @return
     */
    public Category findById(Integer id);
    /**
     * 修改
     * @param category
     * @return
     */
    public int update(Category category);
    /**
     * 删除
     * @param id
     * @return
     */
    public int delete(Integer id);
}

实现类

package com.lxs.travel.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.lxs.travel.dao.CategoryDao;
import com.lxs.travel.domain.Category;
import com.lxs.travel.service.CategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class CategoryServiceImpl implements CategoryService {
    @Autowired
    private CategoryDao categoryDao;
    @Override
    public List<Category> find() {
        return categoryDao.selectList(Wrappers.query());
    }
    @Override
    public int add(Category category) {
        return categoryDao.insert(category);
    }
    @Override
    public Category findById(Integer id) {
        return categoryDao.selectById(id);
    }
    @Override
    public int update(Category category) {
        return categoryDao.updateById(category);
    }
    @Override
    public int delete(Integer id) {
        return categoryDao.deleteById(id);
    }
}

controller

package com.lxs.travel.controller;

import com.lxs.travel.domain.Category;
import com.lxs.travel.service.CategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@Controller
@RequestMapping("/admin/category")
public class CategoryController {
    @Autowired
    private CategoryService categoryService;
    @RequestMapping("/list")
    public String find(Model model) {
        List<Category> list = categoryService.find();
        model.addAttribute("list", list);
        return "/category/list";
    }
    @RequestMapping("/toadd")
    public String toAdd() {
        return "/category/add";
    }
    @RequestMapping("/doadd")
    public String doAdd(Category category) {
        categoryService.add(category);
        return "redirect:/admin/category/list";
    }
    @RequestMapping("/toupdate")
    public String toUpdate(Integer id, Model model) {
        Category category = categoryService.findById(id);
        model.addAttribute("category", category);
        return "/category/update";
    }
    @RequestMapping("/doupdate")
    public String doUpdate(Category category) {
        categoryService.update(category);
        return "redirect:/admin/category/list";
    }
    @RequestMapping("delete")
    public String delete(Integer id) {
        categoryService.delete(id);
        return "redirect:/admin/category/list";
    }
}

页面

页面代码直接从素材拷贝即可,注意分类因为数据较少,可以不用分页

六:旅游线路(重点)

需求和表结构

旅游线路主表(线路名称,详情,介绍,价格,缩略图)

旅游线详细图片表(小图,大图)

实体类

线路实体类

package com.lxs.travel.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;
import java.util.List;

@Data
@TableName("tab_route")
public class Route implements Serializable {
    @TableId(type = IdType.AUTO)
    private Integer rid;//线路id,必输
    private String rname;//线路名称,必输
    private Double price;//价格,必输
    private String routeIntroduce;//线路介绍
    private String rflag; //是否上架,必输,0代表没有上架,1代表是上架
    private String rdate; //上架时间
    private String isThemeTour;//是否主题旅游,必输,0代表不是,1代表是
    private Integer count;//收藏数量
    private Integer cid;//所属分类,必输
    private String rimage;//缩略图
    private Integer sid;//所属商家
    private String sourceId;//抓取数据的来源id
    @TableField(exist = false)
    private Category category;//所属分类 使用resultmap的assocation处理
    @TableField(exist = false)
    private Seller seller;//所属商家 使用resultmap的assocation处理
    @TableField(exist = false)
    private List<RouteImg> routeImgList;//商品详情图片列表,关联属性,mybatis plus不能查,需要配置resultmap使用resultmap的collection处理
}

线路的图片列表

package com.lxs.travel.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;

@Data
@TableName("tab_route_img")
public class RouteImg implements Serializable {
    @TableId(type = IdType.AUTO)
    private int rgid;//商品图片id
    private int rid;//旅游商品id
    private String bigpic;//详情商品大图
    private String smallpic;//详情商品小图
}

dao

线路dao

package com.lxs.travel.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lxs.travel.domain.Route;

import java.util.List;

public interface RouteDao extends BaseMapper<Route> {
    /**
     * 分页查询
     * @param conditioin
     * @return
     */
    public List<Route> find(Route conditioin);
    /**
     * 根据ID查询用户
     * @param id
     * @return
     */
    public Route findById(Integer id);
}

映射文件

因为线路需要查询线路详细图片列表 routeImgList ,线路所属分类 category ,线路所属旅行社 seller ,这里在xml映射文件中使用resultMap的association和collection查询,不能使用mybatis plus内置查询

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lxs.travel.dao.RouteDao">
    <sql id="selectSql">
        SELECT
        *
        FROM
        tab_route
    </sql>
    <select id="find" resultMap="routeMap">
        <include refid="selectSql"></include>
        <where>
            <if test="cid !=null">
                cid = #{cid}
            </if>
            <if test="sid !=null">
                and sid = #{sid}
            </if>
            <if test="rname !=null and rname.trim() != ''">
                and rname like '%${rname}%'
            </if>
            <if test="routeIntroduce != null and routeIntroduce.trim() != ''">
                and routeIntroduce like '%${routeIntroduce}%'
            </if>
        </where>
    </select>
    <resultMap id="routeMap" type="route">
        <id column="rid" property="rid"></id>
        <association property="category" javaType="category"
                     select="com.lxs.travel.dao.CategoryDao.findById" column="cid">
            <id column="cid" property="cid"></id>
        </association>
        <association property="seller" javaType="seller"
                     select="com.lxs.travel.dao.SellerDao.findById" column="sid">
            <id column="sid" property="sid"></id>
        </association>
        <collection property="routeImgList" javaType="java.util.List" ofType="RouteImg"
                    select="com.lxs.travel.dao.RouteImgDao.findByRid" column="rid">
            <id column="rgid" property="rgid"></id>
        </collection>
    </resultMap>
    <select id="findById" parameterType="int" resultMap="routeMap">
        <include refid="selectSql"></include>
        where
        rid = #{rid}
    </select>
</mapper>

注意:这里因为要查询旅游线路的所属分类( select="cn.lxs.travel.dao.CategoryDao.findById" ),所属旅行社( select="cn.lxs.travel.dao.SellerDao.findById" ),线路详细图片列表

( select="cn.lxs.travel.dao.RouteImgDao.findByRid" )

所以需要分在在CategoryDao中增加findById方法如下:

package com.lxs.travel.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lxs.travel.domain.Category;
import org.apache.ibatis.annotations.Select;

public interface CategoryDao extends BaseMapper<Category> {

    @Select("SELECT cname,cid FROM tab_category WHERE cid=#{id}")
    public Category findById(Integer id);

}

SellerDao增加findById方法如下:

package com.lxs.travel.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lxs.travel.domain.Seller;
import org.apache.ibatis.annotations.Select;

public interface SellerDao extends BaseMapper<Seller> {

    @Select("SELECT * FROM tab_seller WHERE sid=#{id}")
    public Seller findById(Integer id);

}

RouteImgDao增加findByRid方法:如下

package com.lxs.travel.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lxs.travel.domain.RouteImg;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface RouteImgDao extends BaseMapper<RouteImg> {

    @Select("select * from tab_route_img where rid = #{rid}")
    public List<RouteImg> findByRid(Integer rid);
}

service

线路service:接口

package com.lxs.travel.service;

import com.github.pagehelper.PageInfo;
import com.lxs.travel.domain.Route;

public interface RouteService {
    /**
     * 分页查询
     * @param conditioin 查询条件
     * @return
     */
    public PageInfo<Route> findPage(Route conditioin, int pageNum, int pageSize);
    /**
     * 添加
     * @param route
     * @return
     */
    public int add(Route route);/**
     * 根据ID查询用户
     * @param id
     * @return
     */
    public Route findById(Integer id);
    /**
     * 修改
     * @param route
     * @return
     */
    public int update(Route route);
    /**
     * 删除
     * @param id
     * @return
     */
    public int delete(Integer id);
}

线路service实现类

package com.lxs.travel.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.lxs.travel.dao.RouteDao;
import com.lxs.travel.domain.Route;
import com.lxs.travel.service.RouteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class RouteServiceImpl implements RouteService {
    @Autowired
    private RouteDao routeDao;
    @Override
    public PageInfo<Route> findPage(Route conditioin, int pageNum, int pageSize) {
        return PageHelper.startPage(pageNum, pageSize).doSelectPageInfo(() -> {
            routeDao.find(conditioin);
        });
    }
    @Override
    public int add(Route route) {
        return routeDao.insert(route);
    }
    @Override
    public Route findById(Integer id) {
        return routeDao.findById(id);
    }
    @Override
    public int update(Route route) {
        return routeDao.updateById(route);
    }
    @Override
    public int delete(Integer id) {
        return routeDao.deleteById(id);
    }
}

测试

package com.lxs.travel.service.impl;

import com.github.pagehelper.PageInfo;
import com.lxs.travel.domain.Route;
import org.junit.Test;
import com.lxs.travel.service.RouteService;
import junit.framework.TestCase;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class RouteServiceImplTest extends TestCase {
    @Autowired
    private RouteService routeService;


    @Test
    public void findPage() {
        Route condition = new Route();
        condition.setRname("北京");
        PageInfo<Route> page = routeService.findPage(condition, 1, 10);
        page.getList().forEach((r) -> {
            System.out.println(r.getRid() + "\t" + r.getRname() + "\t" + r.getCategory().getCname() + "\t" + r.getSeller().getSname() + "\t" + r.getRouteImgList().size());
        });
    }
    @Test
    public void findById() {
        Route r = routeService.findById(34);
        System.out.println(r.getRid() + "\t" + r.getRname() + "\t" + r.getCategory().getCname() +
                "\t" + r.getSeller().getSname() + "\t" + r.getRouteImgList().size());
    }
}

controller

package com.lxs.travel.controller;

import com.github.pagehelper.PageInfo;
import com.lxs.travel.domain.Category;
import com.lxs.travel.domain.Route;
import com.lxs.travel.domain.RouteImg;
import com.lxs.travel.domain.Seller;
import com.lxs.travel.service.CategoryService;
import com.lxs.travel.service.RouteImgService;
import com.lxs.travel.service.RouteService;
import com.lxs.travel.service.SellerService;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Controller
@RequestMapping("/admin/route/")
public class RouteController {
    @Autowired
    private RouteService routeService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private SellerService sellerService;
    @Autowired
    private RouteImgService imgService;
    /**
     * 分页
     * @param route* @param pageNum
     * @param pageSize
     * @param model
     * @return
     */
    @RequestMapping("/page")
    public String page(
            Route route,
            @RequestParam(defaultValue = "1") Integer pageNum,
            @RequestParam(defaultValue = "10") Integer pageSize,
            Model model) {
        PageInfo<Route> page = routeService.findPage(route, pageNum, pageSize);
        model.addAttribute("page", page);
        //查询所有分类生成下拉框
        List<Category> categories = categoryService.find();
        model.addAttribute("categories", categories);
        List<Seller> sellers = sellerService.find(new Seller());
        model.addAttribute("sellers", sellers);
        //用于页面回显
        model.addAttribute("route", route);
        return "route/list";
    }
    /**
     * 删除
     * @param id
     * @return
     */
    @RequestMapping("/delete/{id}")
    public String delete(@PathVariable("id") Integer id) {
        routeService.delete(id);
        return "redirect:/admin/route/page";
    }
    /**
     * 跳到添加页面
     * @param model
     * @return
     */
    @RequestMapping("/toadd")
    public String toAdd(Model model) {
        //查询所有分类生成下拉框
        List<Category> categories = categoryService.find();
        model.addAttribute("categories", categories);
        List<Seller> sellers = sellerService.find(new Seller());
        model.addAttribute("sellers", sellers);
        return "route/add";
    }/**
     * 执行添加
     * @param route
     * @param rimageFile
     * @param request
     * @return
     * @throws IOException
     */
    @RequestMapping("/doadd")
    public String doAdd(Route route, @RequestParam("rimageFile") MultipartFile rimageFile, HttpServletRequest request) throws IOException {
        performRImage(route, rimageFile, request);
        routeService.add(route);
        return "redirect:/admin/route/page";
    }

    private void performRImage(Route route, MultipartFile rimageFile, HttpServletRequest request) throws IOException {
        //项目的部署的目录 + img/product/rimage/
        String savePath = request.getServletContext().getRealPath("img/product/rimage/");
        //处理文件名重复
        String fileName= UUID.randomUUID().toString().replace("-","") + "." + FilenameUtils.getExtension(rimageFile.getOriginalFilename());

        //上传目录不存在先创建
        File savePathDir = new File(savePath);
        if(!savePathDir.exists()){
            savePathDir.mkdirs();
        }
        //保存文件
        rimageFile.transferTo(new File(savePathDir,fileName));
        //设置route的rimage属性=图片相对路径
        route.setRimage("img/product/rimage/"+fileName);
    }

    /**
     * 根据id查询,跳转到修改页面
     * @param id
     * @param model
     * @return
     */
    @RequestMapping("/toupdate/{id}")
    public String toUpdate(@PathVariable Integer id, Model model) {
        //查询所有分类生成下拉框
        List<Category> categories = categoryService.find();
        model.addAttribute("categories", categories);
        List<Seller> sellers = sellerService.find(new Seller());
        model.addAttribute("sellers", sellers);
        Route route = routeService.findById(id);
        model.addAttribute("route", route);
        return "route/update";
    }
    @RequestMapping("/doupdate")
    public String doUpdate(Route route, @RequestParam("rimageFile") MultipartFile rimageFile,HttpServletRequest request) throws IOException {
        performRImage(route, rimageFile, request);
        routeService.update(route);
        return "redirect:/admin/route/page";
    }
    /**
     * 根据id加载线路图片,跳到image.html
     * @param id
     * @param model
     * @return
     */
    @RequestMapping("/toimage/{id}")
    public String toImage(@PathVariable("id") Integer id, Model model) {
        Route route = routeService.findById(id);
        model.addAttribute("route", route);
        return "route/image";
    }
    @RequestMapping("/doimage")
    public String doImage(
            Integer rid,
            @RequestParam("bigPicFile") MultipartFile[] bigPicFile,
            @RequestParam("smallPicFile")MultipartFile[] smallPicFile,
            HttpServletRequest request) throws Exception {

        List<String> bigPic = new ArrayList<>();
        List<String> smallPic = new ArrayList<>();

        String path = request.getServletContext().getRealPath("/");
        for (MultipartFile f : bigPicFile) {
            File bigPath = new File(path + "img\\product\\big-pic\\");
            if (!bigPath.exists()) {
                bigPath.mkdirs();
            }
            String fileName = UUID.randomUUID().toString().replace("-", "") + "." + FilenameUtils.getExtension(f.getOriginalFilename());
            f.transferTo(new File(bigPath, fileName));
            bigPic.add("img/product/big-pic/" + fileName);
        }
        for (MultipartFile f : smallPicFile) {
            File smallPath = new File(path + "img\\product\\small-pic\\");
            if (!smallPath.exists()) {smallPath.mkdirs();
            }
            String fileName = UUID.randomUUID().toString().replace("-", "") + "." + FilenameUtils.getExtension(f.getOriginalFilename());
            f.transferTo(new File(smallPath, fileName));
            smallPic.add("img/product/small-pic/" + fileName);
        }
        //要添加的图片列表
        List<RouteImg> ris = new ArrayList<>();
        for (int i=0; i<bigPic.size(); i++) {
            RouteImg img = new RouteImg();
            img.setRid(rid);
            img.setBigpic(bigPic.get(i));
            img.setSmallpic(smallPic.get(i));
            ris.add(img);
        }
        imgService.saveImg(rid, ris);
        return "redirect:/admin/route/page";
    }
}

主图(缩略图)上传

项目图片文件上传,注意重复文件名的处理

页面

页面使用基于bootstrap的图片上传插件fileinput

参考官方文档

bootstrap-fileinput是一款非常优秀的HTML5文件上传插件,支持文件预览、多选等一系列特性
一款非常优秀的HTML5文件上传插件,支持bootstrap 3.x 和4.x版本,具有非常多的特性:多文件选择。这个插件能最简单的帮你完成文件上传功能,且使用bootstrap样式。还支持多种文件的预览,images, text, html, video,audio, flash。另外还支持ajax方式上传文件,可以看到上传进度。支持拖拽的方式添加和删除文件

用法

如果你将一个 css class='file' 属性赋予 input 标签,插件将自动把字段 [input type="file"] 转换为文件输入控件。但是,如果你想通过 javascript 单独初始化插件,那么请勿将 css class='file' 属性附加到'input'上(因为这将导致重复的初始化,并且JavaScript代码可能会被跳过不执行)

步骤一:

<script src="/assets/js/bootstrap.min.js"></script>
<link href="/js/fileinput/css/fileinput.css" media="all" rel="stylesheet" type="text/css" />
<script src="/js/fileinput/js/fileinput.js" type="text/javascript"></script>
<script src="/js/fileinput/js/fileinput_locale_zh.js" type="text/javascript"></script>

步骤二:

方法一:在文件域中设置class="file"

<input id="rimageFile" name="rimageFile" class="file" type="file">

注意html的input属性multiple,决定fileinput是否接受多图片上传

方法二:使用js把文件域转换成fileinput对象

<input id="rimageFile" name="rimageFile" type="file" >
<script >
    $(function(){
        $("#rimageFile").fileinput({
        });
    })
</script>

修改

加载数据,调到修改页面

    @RequestMapping("/toupdate/{id}")
    public String toUpdate(@PathVariable Integer id, Model model) {
        //查询所有分类生成下拉框
        List<Category> categories = categoryService.find();
        model.addAttribute("categories", categories);
        List<Seller> sellers = sellerService.find(new Seller());
        model.addAttribute("sellers", sellers);
        Route route = routeService.findById(id);
        model.addAttribute("route", route);
        return "route/update";
    }

修改回显主图(缩略图)到页面

                        <script th:inline="javascript">
                            $(function(){
                                var rimage = '/' + [[${route.rimage}]];
                                $("#rimageFile").fileinput({
                                    initialPreview: [
                                        "<img src='" + rimage +"' class='file-preview-image' >"
                                    ],
                                    overwriteInitial: true
                                });
                            })
                        </script>

initialPreview:数组类型,指定初始化回显的图片列表

overwriteInitial:覆盖之前回显的内容

七:线路详细图片

需求: 一条旅游线路,有多张介绍线路的详细图片,详细图片分为小图和大图,前端选择小图可以预览大图

数据结构

service:

package com.lxs.travel.service;

import com.lxs.travel.domain.RouteImg;

import java.util.List;

public interface RouteImgService {

    /**
     * 处理图片
     * @param rid 根据线路id 删除原图
     * @param routeImgs 要添加的新图列表
     */
    public void saveImg(Integer rid, List<RouteImg> routeImgs);
}

实现类:

package com.lxs.travel.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.lxs.travel.dao.RouteImgDao;
import com.lxs.travel.domain.RouteImg;
import com.lxs.travel.service.RouteImgService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class RouteImgServiceImpl implements RouteImgService {

    @Autowired
    private RouteImgDao imgDao;

    @Override
    @Transactional
    public void saveImg(Integer rid, List<RouteImg> routeImgs) {
        imgDao.delete(Wrappers.<RouteImg>query().eq("rid",rid));
        for (RouteImg routeImg : routeImgs) {
            imgDao.insert(routeImg);
        }
    }
}

controller和页面

查看线路详细图片:

/**
     * 根据id加载线路图片,跳到image.html
     * @param id
     * @param model
     * @return
     */
    @RequestMapping("/toimage/{id}")
    public String toImage(@PathVariable("id") Integer id, Model model) {
        Route route = routeService.findById(id);
        model.addAttribute("route", route);
        return "route/image";
    }

页面回显image.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta charset="utf-8" />
    <title>商品详细图片</title>

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />

    <!-- bootstrap & fontawesome -->
    <link rel="stylesheet" href="/assets/css/bootstrap.min.css" />
    <link rel="stylesheet" href="/assets/font-awesome/4.5.0/css/font-awesome.min.css" />

    <!-- page specific plugin styles -->

    <!-- text fonts -->
    <link rel="stylesheet" href="/assets/css/fonts.googleapis.com.css" />

    <!-- ace styles -->
    <link rel="stylesheet" href="/assets/css/ace.min.css" class="ace-main-stylesheet" id="main-ace-style" />

    <!--[if lte IE 9]>
    <link rel="stylesheet" href="/assets/css/ace-part2.min.css" class="ace-main-stylesheet" />
    <![endif]-->
    <link rel="stylesheet" href="/assets/css/ace-skins.min.css" />
    <link rel="stylesheet" href="/assets/css/ace-rtl.min.css" />

    <!--[if lte IE 9]>
    <link rel="stylesheet" href="/assets/css/ace-ie.min.css" />
    <![endif]-->

    <!-- inline styles related to this page -->

    <!-- ace settings handler -->
    <script src="/assets/js/ace-extra.min.js"></script>

    <!-- HTML5shiv and Respond.js for IE8 to support HTML5 elements and media queries -->

    <!--[if lte IE 8]>
    <script src="/assets/js/html5shiv.min.js"></script>
    <script src="/assets/js/respond.min.js"></script>
    <![endif]-->

    <!--[if !IE]> -->
    <script src="/assets/js/jquery-2.1.4.min.js"></script>

    <!-- <![endif]-->

    <!--[if IE]>
    <script src="/assets/js/jquery-1.11.3.min.js"></script>
    <![endif]-->
    <script src="/assets/js/bootstrap.min.js"></script>

    <!-- page specific plugin scripts -->
    <script src="/assets/js/jquery.dataTables.min.js"></script>
    <script src="/assets/js/jquery.dataTables.bootstrap.min.js"></script>
    <script src="/assets/js/dataTables.buttons.min.js"></script>
    <script src="/assets/js/buttons.flash.min.js"></script>
    <script src="/assets/js/buttons.html5.min.js"></script>
    <script src="/assets/js/buttons.print.min.js"></script>
    <script src="/assets/js/buttons.colVis.min.js"></script>
    <script src="/assets/js/dataTables.select.min.js"></script>

    <!-- ace scripts -->
    <script src="/assets/js/ace-elements.min.js"></script>
    <script src="/assets/js/ace.min.js"></script>

    <script language="javascript" type="text/javascript" src="/js/My97DatePicker/WdatePicker.js"></script>

    <link href="/js/fileinput/css/fileinput.css" media="all" rel="stylesheet" type="text/css" />
    <script src="/js/fileinput/js/fileinput.js" type="text/javascript"></script>
    <script src="/js/fileinput/js/fileinput_locale_zh.js" type="text/javascript"></script>

</head>

<body class="no-skin">

<div th:replace="header :: navbar"></div>

<div class="main-container ace-save-state" id="main-container">
    <script type="text/javascript">
        try{ace.settings.loadState('main-container')}catch(e){}
    </script>

    <div th:replace="left :: sidebar"></div>

    <div class="main-content">
        <div class="main-content-inner">
            <div class="breadcrumbs ace-save-state" id="breadcrumbs">
                <ul class="breadcrumb">
                    <li>
                        <i class="ace-icon fa fa-home home-icon"></i>
                        <a href="#">首页</a>
                    </li>

                    <li>
                        <a href="#">用户</a>
                    </li>
                    <li class="active">用户管理</li>
                </ul><!-- /.breadcrumb -->

            </div>

            <div class="page-content">

                <form action="/admin/route/doimage" enctype="multipart/form-data" method="post">
                    <!-- TODO 处理隐藏域,记录线路ID -->
                    <input type="hidden" name="rid" id="rid" th:value="${route.rid}">
                    <div class="form-group">
                        <label for="bigPicFile">详细大图:</label>
                        <input id="bigPicFile" name="bigPicFile" type="file" multiple >
                    </div>
                    <div class="form-group">
                        <label for="smallPicFile">详细小图:</label>
                        <input id="smallPicFile" name="smallPicFile" type="file" multiple  >
                    </div>

                    <div class="form-group" style="text-align: center">
                        <input class="btn btn-primary" type="submit" value="提交" />
                        <input class="btn btn-default" type="reset" value="重置" />
                        <input class="btn btn-default" type="button" value="返回" />
                    </div>
                </form>

            </div><!-- /.page-content -->
            <!-- TODO 处理详细图片回显 -->
            <script th:inline="javascript">
                var ri = [[${route.routeImgList}]]; //后台查询的图片列表
                var bi = []; //回显的大图数组
                var si = []; //回显的小图数组
                for (var i = 0; i < ri.length; i++) {
                    bi.push("<img src='/" + ri[i].bigpic +"' class='file-preview-image' >");
                    si.push("<img src='/" + ri[i].smallpic +"' class='file-preview-image' >");
                }
                $("#bigPicFile").fileinput({
                    initialPreview: bi,
                    overwriteInitial: true,
                    minFileCount: 1, //文件上传最少
                    maxFileCount: 4  //文件上传最多
                });$("#smallPicFile").fileinput({
                    initialPreview: si,
                    overwriteInitial: true,
                    minFileCount: 1,
                    maxFileCount: 4
                });
            </script>


        </div>
    </div><!-- /.main-content -->

</div><!-- /.main-container -->

</body>
</html>

注意html5属性multiple,表示可以多文件上传

保存线路详细图片

    @RequestMapping("/doimage")
    public String doImage(
            Integer rid,
            @RequestParam("bigPicFile") MultipartFile[] bigPicFile,
            @RequestParam("smallPicFile")MultipartFile[] smallPicFile,
            HttpServletRequest request) throws Exception {

        List<String> bigPic = new ArrayList<>();
        List<String> smallPic = new ArrayList<>();

        String path = request.getServletContext().getRealPath("/");
        for (MultipartFile f : bigPicFile) {
            File bigPath = new File(path + "img\\product\\big-pic\\");
            if (!bigPath.exists()) {
                bigPath.mkdirs();
            }
            String fileName = UUID.randomUUID().toString().replace("-", "") + "." + FilenameUtils.getExtension(f.getOriginalFilename());
            f.transferTo(new File(bigPath, fileName));
            bigPic.add("img/product/big-pic/" + fileName);
        }
        for (MultipartFile f : smallPicFile) {
            File smallPath = new File(path + "img\\product\\small-pic\\");
            if (!smallPath.exists()) {smallPath.mkdirs();
            }
            String fileName = UUID.randomUUID().toString().replace("-", "") + "." + FilenameUtils.getExtension(f.getOriginalFilename());
            f.transferTo(new File(smallPath, fileName));
            smallPic.add("img/product/small-pic/" + fileName);
        }
        //要添加的图片列表
        List<RouteImg> ris = new ArrayList<>();
        for (int i=0; i<bigPic.size(); i++) {
            RouteImg img = new RouteImg();
            img.setRid(rid);
            img.setBigpic(bigPic.get(i));
            img.setSmallpic(smallPic.get(i));
            ris.add(img);
        }
        imgService.saveImg(rid, ris);
        return "redirect:/admin/route/page";
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/167196.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

测试开发 | 专项测试技术初识Hook

本文节选自霍格沃兹测试学院内部教材Hook 技术需要预先分析目标应用的源代码和逻辑&#xff0c;根据目标测试场景设置目标、逻辑和数据&#xff0c;然后运行时动态的对目标函数参数值、逻辑或者返回值做修改&#xff0c;达到修改现有函数逻辑、实现目标测试场景的目的。Hook的价…

JavaWeb基础(一) Mybatis使用详解

JavaWeb基础——Mybatis 1&#xff0c;配置文件实现CRUD 如上图所示产品原型&#xff0c;里面包含了品牌数据的 查询 、按条件查询、添加、删除、批量删除、修改 等功能&#xff0c;而这些功能其实就是对数据库表中的数据进行CRUD操作。接下来我们就使用Mybatis完成品牌数据的…

3-2存储系统-主存与CPU的连接外部存储器

文章目录一.主存与CPU的连接&#xff08;一&#xff09;连接原理&#xff08;二&#xff09;主存容量的扩展1.位扩展法2.字扩展法3.字位同时扩展法&#xff08;三&#xff09;存储芯片的地址分配和片选1.线选法2.译码片选法二.外部存储器&#xff08;一&#xff09;磁盘储存器1…

JVM-三色标记

一、什么叫三色标记三色也叫三色抽象&#xff0c;它是所有mutator和collector都必须遵守的定律。它把对象标记为三种颜色&#xff1a;白色&#xff1a;对象还未被垃圾收集器访问&#xff0c;在回收的开始阶段所有的对象均为白色&#xff08;当然了这只是指概念上的&#xff0c;…

PaddleNLP开源UTC通用文本分类技术,斩获ZeroCLUE、FewCLUE双榜第一

飞桨PaddlePaddle 2023-01-12 20:02 发表于湖北 针对产业级分类场景中任务多样、数据稀缺、标签迁移难度大等挑战&#xff0c;百度提出了一个大一统的通用文本分类技术UTC&#xff08;Universal Text Classfication&#xff09;。 UTC在ZeroCLUE和FewCLUE两个榜单上均位居榜首…

css加载会造成阻塞吗?

目录 A.设置网络加载速度 B.css加载会阻塞DOM树的解析渲染吗&#xff1f; 1.css会阻塞DOM树解析&#xff1f; 2.css加载会阻塞DOM树渲染&#xff1f; 3.个人对这种机制的评价 3.css加载会阻塞js运行吗&#xff1f; 4.结论 可以使用以下几种方法解决CSS加载速度的问题: …

曲线曲率介绍和python求法

目录曲率1.1 弧长参数 s参考资料曲率 比如我们想知道曲线 AB\boldsymbol{AB}AB 上任一点处的弯曲程度怎么办呢&#xff1f;这时就需要一个十分重要的概念——曲率。 维基百科&#xff1a; 在数学中&#xff0c;曲率&#xff08;curvature&#xff09;是描述几何体弯曲程度的量…

Octave安装与使用

1. 介绍 Octave是一种编程语言&#xff0c;旨在解决线性和非线性的数值计算问题。Octave为GNU项目下的开源软件&#xff0c;早期版本为命令行交互方式&#xff0c;4.0.0版本发布基于QT编写的GUI交互界面。Octave语法与Matlab语法非常接近&#xff0c;可以很容易的将matlab程序…

机器学习/人工智能 实验二:图像特征自动学习方法实践与分析

写在前面 参考的是https://zh.d2l.ai/index.html 一、实验目的与要求 (1)利用基于深度学习的特征自动学习方法完成图像特征提取的实验方案的设计。 (2)编程并利用相关软件完成实验测试&#xff0c;得到实验结果。 (3)通过对实验数据的分析、整理&#xff0c;得出实验结论&am…

Unity | 序列化(Serialized)和反序列化(NonSerialized)是什么意思

一、什么是序列化 官方叙述&#xff1a;序列化是将对象的状态信息转换为可以存储或传输的形式的过程。 人话叙述&#xff1a;我们平时输入的代码&#xff0c;实际上是不能储存或者传输的&#xff0c;所以我们需要翻译一下&#xff0c;翻译成能储存或者翻译的文字&#xff0c;这…

【SpringBoot 学习】52、SpringBoot 使用 grpc 实现远程服务调用

文章目录一、SpringBoot 使用 grpc 实现远程服务调用1、服务端编写2、客户端编写一、SpringBoot 使用 grpc 实现远程服务调用 gRPC 是一个现代的、开源的、高性能的远程过程调用&#xff08;RPC&#xff09;框架&#xff0c;可以在任何地方运行。gRPC 使客户端和服务器应用程序…

Java-Thread多线程的使用

Java-Thread多线程的使用一、线程&#xff0c;进程&#xff0c;并发&#xff0c;并行的概念1.进程2.线程3.并发和并行二、线程的创建和使用1.通过继承Thread类&#xff0c;重写run方法2.实现Runnable接口&#xff0c;重写run方法3.使用案例三、线程的常用方法四、线程的退出和中…

关于机器人状态估计(11)-VIO单目与双目/雷达Lidar SLAM/未来的机器人

写这篇文章的时候刚发生行业大事件&#xff1a; Google收购ROS 其实一开始还是水&#xff0c;绝对大量文不对题&#xff0c;但是必有干货&#xff0c;毕竟用的是这个关键的系列标题。 最近有几件行业内发生的大小事&#xff0c;让我觉得有必要更一下。 首先是Livox的mid-360…

VueUse(中文)——核心函数:State相关函数

VueUse官方地址 一、createGlobalState 将状态保持在全局范围内&#xff0c;以便跨Vue实例重用 1、没有持久性(存储在内存中) 例如&#xff1a; 或者 2、持久性存储 使用useStorage()存储在localStorage:例如&#xff1a; 组件使用&#xff1a; 二、createInjectionSt…

【图灵商城】前、后端项目搭建与运行

【图灵商城】前、后端项目搭建与运行 项目介绍 图灵商城-基础班架构图&#xff0c;如下所示&#xff1a; 本节是项目代码的初始化&#xff0c;今天是2023-01-15&#xff0c;先预祝大家新年快乐&#xff01;&#xff01;&#xff01; 图灵商城这个项目是一个前后端分离的项目…

我这是这样知道 React TS 中的 Event Handler 类型的

开头 现在 TypeScript 的发展也越来越成熟&#xff0c;已逐渐应用到我们开发的前端项目之中&#xff0c;它能够带来类型提示&#xff0c;提前规避类型上的错误&#xff0c;来提高项目代码的健壮性&#xff0c;以及更高效的编码效率&#xff0c;前提就是我们需要定义好相应的类…

创客匠人赋能线上瑜伽健身实现流量增长

近年来&#xff0c;我国的儿童、成年人肥胖率逐年攀升。身边发胖的人越来越多&#xff0c;尤其是步入中年的人群&#xff0c;很多都有“发福”的现象。 超重肥胖已经成为影响我国居民健康的重要公共卫生问题。在身材焦虑和疫情肆虐下&#xff0c;很多人开始重视自己的健康问题…

python学习笔记---Python基础【廖雪峰】

Python基础 数据类型和变量 整数 对于很大的数&#xff0c;例如10000000000&#xff0c;很难数清楚0的个数。Python允许在数字中间以_分隔&#xff0c;因此&#xff0c;写成10_000_000_000和10000000000是完全一样的。十六进制数也可以写成0xa1b2_c3d4。 >>> prin…

Qt opencv编译详细教程(windows版)

在Qt中使用opencv这个算法视觉库&#xff0c;前期环境步骤搭建如下&#xff1a; 1、下载cmake。 2、下载opencv库&#xff0c;我这里下载的是opencv-3.3.1版本。 3、没有安装Qt的下载Qt软件&#xff0c;Qt的环境安装部署&#xff0c;这里不做介绍。 4、安装cmake后&#xff0c;…

python学习笔记---IO编程【廖雪峰】

IO编程 ​ IO在计算机中指Input/Output&#xff0c;也就是输入和输出。由于程序和运行时数据是在内存中驻留&#xff0c;由CPU这个超快的计算核心来执行&#xff0c;涉及到数据交换的地方&#xff0c;通常是磁盘、网络等&#xff0c;就需要IO接口。 ​ IO编程中&#xff0c;S…