目录
1、项目需求
用户展示旅游线路展示线路图片上传与删除线路分类 展示旅行社展示
2、技术需求
前台有的老,学技术就可以了
后台技术springboot 、 mybatis-plus前台bootstrap 、 jquery 、 thymeleaf 、 fifileinput 插件数据库mysql
3、pom.xml
<groupId>com.qinluyu</groupId>
<artifactId>SpringBoot04</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- war/jar类型,可在其他服务器上运行-->
<packaging>war</packaging>
<!-- jdk版本-->
<properties>
<java.version>1.8</java.version>
</properties>
<!--添加父工程坐标-->
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.3.0.RELEASE</version>
<relativePath/>
</parent>
<!--添加web启动器-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- springboot整合数据库-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 测试test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>
<!--配置文件启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<!--分页-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.10</version>
</dependency>
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!--maven-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!--可不加版本号-->
<version>2.5.6</version>
</dependency>
</dependencies>
4、application.yml
server:
port: 9091
servlet:
context-path: /
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/travel?characterEncoding=utf8?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
username: root
password: 123
driver-class-name: com.mysql.jdbc.Driver
hikari:
idle-timeout: 60000
maximum-pool-size: 30
minimum-idle: 10
thymeleaf:
cache: false
mybatis-plus:
mapper-locations: classpath:/mybatis/*.xml
#加载映射文件
type-aliases-package: com.qinluyu.domain
#别名搜索的包
configuration:
lazy-loading-enabled: true
#打开懒加载
aggressive-lazy-loading: false #关闭积极懒加载
4、MybatisPlus的配置文件
/**
* MybatisPlus的配置文件
*/
@Configuration
@MapperScan("com.qinluyu.dao")
public class MybatisPlusConfig {
@Bean
public PageInterceptor pageInterceptor(){
return new PageInterceptor();
}
}
5、springboot中配置日期类型转换器
/**
* springboot中配置日期类型转换器
*/
@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;
}
}
6、用户管理
(1)实体类
@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;
}
(2)Dao类
public interface UserDao extends BaseMapper<User> {
}
(3)Service类
public interface UserService {
/**
* 分页
* @param condition
* @param pageNum
* @param pageSize
* @return user,pageNum,pageSize
*/
public PageInfo<User> findPage(User condition, int pageNum, int pageSize);
/**
* 查询
* @param condition
* @return user
*/
public List<User> find(User condition);
/**
* 添加
* @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);
}
(4)Service的实现类(重写)
@Service
public class UserServiceImpl implements UserService {
/**
* 需要写引用
*/
/*@Autowired
private UserDao userDao;*/
@Resource
private UserDao userDao;
/**
* 分页
* @param condition
* @param pageNum
* @param pageSize
* @return
*/
@Override
public PageInfo<User> findPage(User condition, int pageNum, int pageSize) {
return PageHelper.startPage(pageNum,pageSize).doSelectPageInfo(()->{
userDao.selectList(Wrappers.<User>query());
});
}
/**
* 查询
* @param condition
* @return
*/
@Override
public List<User> find(User condition) {
return userDao.selectList(Wrappers.query());
}
/**
* 增加
* @param user
* @return
*/
@Override
public int add(User user) {
return userDao.insert(user);
}
/**
* 根据id查询
* @param id
* @return
*/
@Override
public User findById(Integer id) {
return userDao.selectById(id);
}
/**
* 更新
* @param user
* @return
*/
@Override
public int update(User user) {
return userDao.updateById(user);
}
/**
* 删除
* @param id
* @return
*/
@Override
public int delete(Integer id) {
return userDao.deleteById(id);
}
}
(5)controller类
@Controller
@RequestMapping("/admin/user")
public class UserController {
@Resource
private UserService userService;
/**
*分页查询
* @param user
* @param pageNum
* @param pageSize
* @param model
* @return
*/
@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";
}
/**
* 跳到添加页面
* @return
*/
@RequestMapping("/toadd")
public String toAdd() {
return "/user/add";
}
/**
* 添加
* @param user
* @return
*/
@RequestMapping("/doadd")
public String doAdd(User user) {
userService.add(user);
return "redirect:/admin/user/page";
}
/**
* 跳到修改页面
* @param id
* @param model
* @return
*/
@RequestMapping("/toupdate/{id}")
public String toUpdate(@PathVariable("id") Integer id, Model model) {
User user = userService.findById(id);
model.addAttribute("user", user);
return "/user/update";
}
/**
* 更新
* @param user
* @return
*/
@RequestMapping("/doupdate")
public String doUpdate(User user) {
userService.update(user);
return "redirect:/admin/user/page";
}
/**
* 删除
* @param id
* @return
*/
@RequestMapping("/delete/{id}")
public String delete(@PathVariable("id") Integer id) {
userService.delete(id);
return "redirect:/admin/user/page";
}
/**
* 批量删除
* @param ids
* @return
*/
@RequestMapping("/delete")
public String batchDelete(@RequestParam("ids") Integer[] ids) {
for (Integer id : ids) {
userService.delete(id);
}return "redirect:/admin/user/page";
}
(6)前端分页
<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.pages}页,每页${page.pageSize}行数|">
</span>
<select id="setRows">
<option value="5" th:selected="${5 == page.pageSize}">5</option>
<option value="10" th:selected="${10 == page.pageSize}">10</option>
<option value="20" th:selected="${20 == page.pageSize}">20</option>
<option value="30" th:selected="${30 == page.pageSize}">30</option>
</select>
</ul>
</nav>
</div>
<script th:inline="javascript">
$(function(){
//初始化变量
var pageNum = [[${page.pageNum}]];
//当前页
var pageCount = [[${page.pages}]];
//最后页
var hasNextPage = [[${page.hasNextPage}]];
//还有下一页
var hasPreviousPage = [[${page.hasPreviousPage}]];
//还有上一页
if (!hasPreviousPage) {
$("#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>
(7)添加(删除)数据后回显
<div class="page-content">
<form action="/admin/user/doupdate" method="post" th:object="${user}">
<input type="hidden" name="uid" th:value="${user.uid}">
<div class="form-group">
<label for="name">姓名:</label>
<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>
7、线路管理
8、旅游公司管理
9、旅游线路管理
(1)图片上传
private void performRImage(Route route, @RequestParam("rimageFile") MultipartFile rimageFile, HttpServletRequest request) throws IOException {
String savePath = request.getServletContext().getRealPath("img/product/rimage/");
String fileName = UUID.randomUUID().toString().replaceAll("-", "") + "." + FilenameUtils.getExtension(rimageFile.getOriginalFilename());
File savePathDir = new File(savePath);
if (!savePathDir.exists()) {
savePathDir.mkdirs();
}
rimageFile.transferTo(new File(savePathDir, fileName));
route.setRimage("img/product/rimage/" + fileName);
}
/**
* 根据id加载线路图片,跳到image.html
* @param id
* @param model
* @return
*/
@RequestMapping("/toimage")
public String toImage(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";
}
10、部分功能……
经测试后,基本功能实现
部分功能还需再写,比如分类管理可以添加、删除却不能修改
图片如果是空,则提交不了
等等