你敢信?开发一个管理系统我只用了两天
推荐关注
以下文章来源Java后端栈,回复”面试“获面试宝典
哈喽,各位新来的小伙伴们,大家好!由于公众号做了改版,为了保证公众号的资源能准时推送到你手里,大家记得将后端君的公众号 加星标置顶 ,在此真诚的表示感谢~
编辑:后端妹 | 来源:Java架构师技术
正文
2. 编写yaml配置文件
server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/supplier?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
username: root
password: root
# thymeleaf 配置
thymeleaf:
# 关闭缓存
cache: false
prefix: classpath:/templates/
mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml
3. 项目初期基本搭建
在搭建一个项目的初期,为了让系统显得更规范化,我一般会提前做好基础的配置和声明,一个项目从开始设想时所涉及到技术以及这些技术对应的一些基础配置,都要提前规划清楚(个人习惯)。比如:异常处理、拦截器、过滤器、常量类等等。
①异常处理
@ControllerAdvice
public class ExceptionHandler {
private final org.slf4j.Logger logger = LoggerFactory.getLogger(this.getClass());
@org.springframework.web.bind.annotation.ExceptionHandler(Exception.class)
public ModelAndView exception(HttpServletRequest request, Exception e ) throws Exception {
logger.error("Request URL:{},Exception:{}",request.getRequestURL(),e);
if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class )!= null){
throw e;
}
ModelAndView mv = new ModelAndView();
mv.addObject("url",request.getRequestURL());
mv.addObject("exception",e);
mv.setViewName("error/error");
return mv;
}
}
② 拦截器
拦截器主要是对一些资源做的处理,类似于某些资源需要用户登录后才能访问的,某些是不需要的,比如:登录功能就不需要有所拦截,而对用户的各种管理就需要添加拦截操作,这样才能使系统的安全性有所提高。
登录拦截
public class LoginInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (request.getSession().getAttribute("user") == null){
response.sendRedirect("/api");
return false;
}
return true;
}
}
资源放行
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/api/**")
.excludePathPatterns("/api","/api/doLogin");
}
}
4. 编写Controller前端控制器代码
首先创建一个FileController类
① 跳转文件上传的页面
//跳转文件上传的页面
@RequestMapping("/file-upload")
public String userList(){
return "file-upload";
}
② 实现文件上传的功能
@RequestMapping("/doAddForUser")
public String doAdd(User user, @RequestParam("file") MultipartFile files, HttpServletRequest request) throws IOException {
//String path = null;
if (files != null && !files.isEmpty()){
String name = UUID.randomUUID().toString().replace("-","");
//获取文件的扩展名
String ext = FilenameUtils.getExtension(files.getOriginalFilename());
//设置文件上传的路径
String url =request.getSession().getServletContext().getRealPath("/upload/");
File file = new File(url);
if (!file.exists()){
file.mkdir();
}
//测试路径
System.out.println(request.getServletPath()+ "/upload");
System.out.println(request.getContextPath() + "/upload/");
//以绝对路径保存重命名后的文件
files.transferTo(new File(url+"/"+name+"."+ext));
user.setAvatar(request.getContextPath() + "/upload/"+name+"."+ext);
}
user.setId(UUID.randomUUID().toString());
String salt = PasswordUtils.getSalt();
String password = user.getPassword();
String encode = PasswordUtils.encode(password, salt);
user.setSalt(salt) ;
user.setPassword(encode);
user.setCreateTime(new Date());
userService.save(user);
return "redirect:/api/users";
}
注:如何想要实现多文件上传需要更改的地方如下:
③ 实现多文件上传功能
在这个项目中并未实现多文件上传功能
private void commons(Object obj, @RequestParam("file") CommonsMultipartFile[] files, HttpServletRequest request) throws IOException {
//String path = null;
for (int i = 0; i < files.length; i++) {
if (files[i] != null && !files[i].isEmpty()){
String name = UUID.randomUUID().toString().replace("-","");
//获取文件的扩展名
String ext = FilenameUtils.getExtension(files[i].getOriginalFilename());
//设置文件上传的路径
String url =request.getSession().getServletContext().getRealPath("/upload/");
File file = new File(url);
if (!file.exists()){
file.mkdir();
}
//测试路径
System.out.println(request.getServletPath()+ "/upload");
System.out.println(request.getContextPath() + "/upload/");
//以绝对路径保存重命名后的文件
files[i].transferTo(new File(url+"/"+name+"."+ext));
if (i == 0){
obj.setUrl1(request.getContextPath() + "/upload/"+name+"."+ext);
}
if (i == 1){
obj.setUrl2(request.getContextPath() + "/upload/"+name+"."+ext);
}
if (i == 2){
obj.setUrl3(request.getContextPath() + "/upload/"+name+"."+ext);
}
if (i == 3){
obj.setUrl4(request.getContextPath() + "/upload/"+name+"."+ext);
}
if (i == 4){
obj.setUrl5(request.getContextPath() + "/upload/"+name+"."+ext);
}
}
}
}
5. 项目优化
对于前后端不分离的项目,多数使用的是页面缓存优化,当系统某一瞬间遭受巨大流量时,当第一个用户进行页面访问时可以将该页面数据进行缓存,这样,后来的用户访问到的页面都是从缓存中获取的,这样就减少了 对数据库的操作,减轻了数据库的压力,从而达到优化的处理。另外,搜索公众号Linux就该这样学后台回复“猴子”,获取一份惊喜礼包。
① 导入依赖
<!--Redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--commons-pools2 对象池依赖-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
② yaml配置
## Redis配置
redis:
# 服务器地址
host: localhost
# 端口
port: 6379
# 数据库
database: 0
# 超时时间
connect-timeout: 10000ms
lettuce:
pool:
# 最大连接数
max-active: 8
# 最大连接阻塞等待时间 默认 -1
max-wait: 10000ms
# 最大空闲时间 默认8
max-idle: 200
# 最小空闲连接 默认8
min-idle: 5
④ Redis序列化处理
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
//key序列化
redisTemplate.setKeySerializer(new StringRedisSerializer());
//value序列化
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
//hash类型key的序列化
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
//hash类型value的序列化
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
}
③ 优化处理
@Autowired
private NewsService newsService;
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private ThymeleafViewResolver viewResolver;
@RequestMapping(value = "/news",produces = "text/html;charset=utf-8")
@ResponseBody
public String roles(Model model, @RequestParam(value = "pageNo",defaultValue = "1")Integer pageNo
, @RequestParam(value = "pageSize",defaultValue = "10")Integer pageSize
, HttpServletRequest request, HttpServletResponse response){
//Redis中获取页面,如果不为空,则直接返回页面
ValueOperations valueOperations = redisTemplate.opsForValue();
String html = (String) valueOperations.get("news-list");
if (!StringUtils.isEmpty(html)){
return html;
}
PageHelper.startPage(pageNo,pageSize);
List<News> list = newsService.list();
PageInfo<News> pageInfo = new PageInfo<>(list);
model.addAttribute("news",list);
model.addAttribute("pageInfo",pageInfo);
//如果为空,手动渲染,存入Redis中并返回
WebContext context = new WebContext(request, response, request.getServletContext(), request.getLocale(), model.asMap());
html = viewResolver.getTemplateEngine().process("news-list", context);
if (!StringUtils.isEmpty(html)){
//给缓存设置过期时间
valueOperations.set("news-list",html,60, TimeUnit.SECONDS);
}
return html;
}
④ Redis查看
6. 注意事项
注意@Controller和@RestController的区别,本项目使用的是模板渲染页面,而@Controller就是用来响应页面的;而@RestController是用来返回Json
在项目优化阶段需要在方法上添加注解@ResponseBody,因为我们是将整个页面进行缓存 ,所以要将页面转换成JSON进行存储。
注入Thymeleaf解析器,将具体的 页面进行解析成Json字符串进行存储
将存入Redis中的数据加上过期时间,因为页面中的数据要和数据库保持一致,如果用户看到是几十秒之前或一分钟之前的数据还是勉强可以接受的。
目前代码已经同步到Gitee:后台回复【供应链】即可获取所有系统
如果有需要的自行前去仓库拉取,还请各位大佬不要吝啬手中的三连哟!
最后,想学习这个项目的可以查看项目地址:
项目源码,怎么领取?
扫码下方二维码,后台回复【供应链】即可获取所有系统
在 GitHub猿 还有更多优质项目系统学习资源,欢迎分享给其他同学吧!
最后给读者整理了一份BAT大厂面试真题,需要的可扫码加微信备注:“面试”获取。
◆ ◆ ◆ ◆ ◆
欢迎添加栈哥个人微信 ysle007 进粉丝群或围观朋友圈
扫码关注带你吊爆Java后端技术