springboot+jsp中文乱码_基于SpringBoot的个人博客搭建(二):后端开发

前言:在之前,我们已经完成了项目的基本准备,那么就可以开始后台开发了,突然又想到一个问题,就是准备的时候只是设计了前台的RESTful APIs,但是后台管理我们同样也是需要API的,那么就在这一篇里面一起实现了吧...

开发准备工作参见上一篇

一些设计上的调整

在查了一些资料和吸收了一些评论给出良好的建议之后,我觉得有必要对一些设计进行一些调整:

  • 1)数据库:命名应该更加规范,比如表示分类最好用category而不是sort,表示评论最好用comment而不是message;
  • 2)RESful APIs:在准备着手开始写后台的时候就已经发现,本来想的是凡是以/api开头的都是暴露出来给前端用的,凡是以/admin开头的都是给后台使用的地址,但是意外的没有设计后天的API也把一些删除命令暴露给了前端,这就不好了重新设计设计;
  • 3)命名规范的问题:因为使用MyBatis逆向工程自动生成的时候,配置了一个useActualColumnNames使用表真正名称的东西,所以整得来生成POJO类基础字段有下划线,看着着实有点不爽,把它给干掉干掉...;

数据库调整

把字段规范了一下,并且删除了分类下是否有效的字段(感觉这种不经常变换的字段留着也没啥用干脆干掉..),所以调整为了下面这个样子(调整字段已标红):

163e3dbe820703dda8a8f000cf9a4c52.png

然后重新使用生成器自动生成对应的文件,注意记得修改generatorConfig.xml文件中对应的数据库名称;

创建和修改时间的字段设置

通过查资料发现其实我们可以通过直接设置数据库来自动更新我们的modified_by字段,并且可以像设置初始值那样给create_by和modified_by两个字段以当前时间戳设置默认值,这里具体以tbl_article_info这张表为例:

CREATE TABLE `tbl_article_info` ( `id` bigint(40) NOT NULL AUTO_INCREMENT COMMENT '主键', `title` varchar(50) NOT NULL DEFAULT '' COMMENT '文章标题', `summary` varchar(300) NOT NULL DEFAULT '' COMMENT '文章简介,默认100个汉字以内', `is_top` tinyint(1) NOT NULL DEFAULT '0' COMMENT '文章是否置顶,0为否,1为是', `traffic` int(10) NOT NULL DEFAULT '0' COMMENT '文章访问量', `create_by` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `modified_by` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改日期', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;

我们通过设置DEFAULT为CURRENT_TIMESTAMP,然后给modified_by字段多添加了一句ON UPDATE CURRENT_TIMESTAMP,这样它就会在更新的时候将该字段的值设置为更新时间,这样我们就不用在后台关心这两个值了,也少写了一些代码(其实是写代码的时候发现可以这样偷懒..hhh...);

RESTful APIs重新设计

我们需要把一些不能够暴露给前台的API收回,然后再设计一下后台的API,捣鼓了一下,最后大概是这个样子了:

后台Restful APIs:

b5cd2caebcbff62e7c9ee6c7247ec657.png

前台开放RESful APIs:

16f7e7a3b05a7465379896855cf14e1d.png

这些API只是用来和前端交互的接口,另外一些关于日志啊之类的东西就直接在后台写就行了,OK,这样就爽多了,可以开始着手写代码了;

基本配置

随着配置内容的增多,我逐渐的想要放弃.yml的配置文件,主要的一点是这东西不好对内容进行分类(下图是简单配置了一些基本文件后的.yml和.properties文件的对比)..

14f84fc487d3476bc09c91989a93a4a7.png

最后还是用回.properties文件吧,不分类还是有点难受

编码设置

我们首先需要解决的是中文乱码的问题,对应GET请求,我们可以通过修改Tomcat的配置文件【server.xml】来把它默认的编码格式改为UTF-8,而对于POST请求,我们需要统一配置一个拦截器一样的东西把请求的编码统一改成UTF-8:

## ——————————编码设置——————————spring.http.encoding.charset=UTF-8spring.http.encoding.force=truespring.http.encoding.enabled=trueserver.tomcat.uri-encoding=UTF-8

但是这样设置之后,在后面的使用当中还是会发生提交表单时中文乱码的问题,在网上搜索了一下找到了解决方法,新建一个【config】包创建下面这样一个配置类:

@Configurationpublic class MyWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter { @Bean public HttpMessageConverter responseBodyConverter() { StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8")); return converter; } @Override public void configureMessageConverters(List> converters) { super.configureMessageConverters(converters); converters.add(responseBodyConverter()); } @Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { configurer.favorPathExtension(false); }}

数据库及连接池配置

决定这一次试试Druid的监控功能,所以给一下数据库的配置:

## ——————————数据库访问配置——————————spring.datasource.type=com.alibaba.druid.pool.DruidDataSourcespring.datasource.driver-class-name = com.mysql.jdbc.Driverspring.datasource.url = jdbc:mysql://127.0.0.1:3306/blog?characterEncoding=UTF-8spring.datasource.username = rootspring.datasource.password = 123456# 下面为连接池的补充设置,应用到上面所有数据源中# 初始化大小,最小,最大spring.datasource.druid.initial-size=5spring.datasource.druid.min-idle=5spring.datasource.druid.max-active=20# 配置获取连接等待超时的时间spring.datasource.druid.max-wait=60000# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒spring.datasource.druid.time-between-eviction-runs-millis=60000# 配置一个连接在池中最小生存的时间,单位是毫秒spring.datasource.druid.min-evictable-idle-time-millis=300000spring.datasource.druid.validation-query=SELECT 1 FROM DUALspring.datasource.druid.test-while-idle=truespring.datasource.druid.test-on-borrow=falsespring.datasource.druid.test-on-return=false# 打开PSCache,并且指定每个连接上PSCache的大小spring.datasource.druid.pool-prepared-statements=truespring.datasource.druid.max-pool-prepared-statement-per-connection-size=20# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙spring.datasource.druid.filters=stat,wall,log4j

日志配置

在SpringBoot中其实已经使用了Logback来作为默认的日志框架,这是log4j作者推出的新一代日志框架,它效率更高、能够适应诸多的运行环境,同时天然支持SLF4J,在SpringBoot中我们无需再添加额外的依赖就能使用,这是因为在spring-boot-starter-web包中已经有了该依赖了,所以我们只需要进行配置使用就好了

第一步:创建logback-spring.xml

当项目跑起来的时候,我们不可能还去看控制台的输出信息吧,所以我们需要把日志写到文件里面,在网上找到一个例子(链接:http://tengj.top/2017/04/05/springboot7/)

<?xml version="1.0" encoding="UTF-8"?>logback%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n${log.path}/logback.%d{yyyy-MM-dd}.log%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n

在Spring Boot中你只要按照规则组织文件名,就能够使得配置文件能够被正确加载,并且官方推荐优先使用带有-spring的文件名作为日志的配置(如上面使用的logback-spring.xml,而不是logback.xml),满足这样的命名规范并且保证文件在src/main/resources下就好了;

第二步:重启项目检查是否成功

我们定义的目录位置为/log/wmyskxz/,但是在项目的根目录下并没有发现这样的目录,反而是在当前盘符的根目录..不是很懂这个规则..总之是成功了的..

199593992fc103d73a2cb02079e06e55.png

打开是密密麻麻一堆跟控制台一样的【info】级别的信息,因为这个系统本身就比较简单,所以就没有必要去搞什么文本切割之类的东西了,ok..日志算是配置完成;

实际测试了一下,上线之后肯定需要调整输出级别的,不然日志文件就会特别大...

拦截器配置

我们需要对地址进行拦截,对所有的/admin开头的地址请求进行拦截,因为这是后台管理的默认访问地址开头,这是必须进行验证之后才能访问的地址,正如上面的RESTful APIs,这里包含了一些增加/删除/更改/编辑一类的操作,而统统这些操作都是不能够开放给用户的操作,所以我们需要对这些地址进行拦截:

第一步:创建User实体类

做验证还是需要添加session,不然不好弄,所以我们还是得创建一个常规的实体:

public class User { private String username; private String password; /* getter and setter */}

第二步:创建拦截器并继承HandlerInterceptor接口

在【interceptor】包下新建一个【BackInterceptor】类并继承HandlerInterceptor接口:

public class BackInterceptor implements HandlerInterceptor { private static String username = "wmyskxz"; private static String password = "123456"; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { boolean flag = true; User user = (User) request.getSession().getAttribute("user"); if (null == user) { flag = false; } else { // 对用户账号进行验证,是否正确 if (user.getUsername().equals(username) && user.getPassword().equals(password)) { flag = true; } else { flag = false; } } return flag; }}

在拦截器中,我们从session中取出了user,并判断是否符合要求,这里我们直接写死了(并没有更改密码的需求,但需要加密),而且我们并没有做任何的跳转操作,原因很简单,根本就不需要跳转,因为访问后台的用户只有我一个人,所以只需要我知道正确的登录地址就可以了...

第三步:在配置类中复写addInterceptors方法

刚才我们在设置编码的时候自己创建了一个继承自WebMvcConfigurerAdapter的设置类,我们需要复写其中的addInterceptors方法来为我们的拦截器添加配置:

@Overridepublic void addInterceptors(InterceptorRegistry registry) { // addPathPatterns 用于添加拦截规则 // excludePathPatterns 用户排除拦截 registry.addInterceptor(new BackInterceptor()).addPathPatterns("/admin/**").excludePathPatterns("/toLogin"); super.addInterceptors(registry);}
  • 说明:这个方法也很简单,通过在addPathPatterns中添加拦截规则(这里设置拦截/admin开头的所有地址),并通过excludePathPatterns来排除拦截的地址(这里为/toLogin,即登录地址,到时候我可以弄得复杂隐蔽一点儿)

第四步:配置登录页面

以前我们在写Spring MVC的时候,如果需要访问一个页面,必须要在Controller中添加一个方法跳转到相应的页面才可以,但是在SpringBoot中增加了更加方便快捷的方法:

/** * 以前要访问一个页面需要先创建个Controller控制类,在写方法跳转到页面 * 在这里配置后就不需要那么麻烦了,直接访问http://localhost:8080/toLogin就跳转到login.html页面了 * * @param registry */@Overridepublic void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/admin/login").setViewName("login.html"); super.addViewControllers(registry);}
  • 注意:login.html记得要放在【templates】下才会生效哦...(我试过使用login绑定视图名不成功,只能写全了...)

访问日志记录

上面我们设置了访问限制的拦截器,对后台访问进行了限制,这是拦截器的好处,我们同样也使用拦截器对于访问数量进行一个统计

第一步:编写前台访问拦截器

对照着数据库的设计,我们需要保存的信息都从request对象中去获取,然后保存到数据库中即可,代码也很简单:

public class ForeInterceptor implements HandlerInterceptor { @Autowired SysService sysService; private SysLog sysLog = new SysLog(); private SysView sysView = new SysView(); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 访问者的IP String ip = request.getRemoteAddr(); // 访问地址 String url = request.getRequestURL().toString(); //得到用户的浏览器名 String userbrowser = BrowserUtil.getOsAndBrowserInfo(request); // 给SysLog增加字段 sysLog.setIp(StringUtils.isEmpty(ip) ? "0.0.0.0" : ip); sysLog.setOperateBy(StringUtils.isEmpty(userbrowser) ? "获取浏览器名失败" : userbrowser); sysLog.setOperateUrl(StringUtils.isEmpty(url) ? "获取URL失败" : url); // 增加访问量 sysView.setIp(StringUtils.isEmpty(ip) ? "0.0.0.0" : ip); sysService.addView(sysView); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); // 保存日志信息 sysLog.setRemark(method.getName()); sysService.addLog(sysLog); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { }}
  • 注意:但是需要注意的是测试的时候别把拦截器开了(主要是postHandle方法中中无法强转handler),不然不方便测试...

BrowserUtil是找的网上的一段代码,直接黏贴复制放【util】包下就可以了:

/** * 用于从Request请求中获取到客户端的获取操作系统,浏览器及浏览器版本信息 * * @author:wmyskxz * @create:2018-06-21-上午 8:40 */public class BrowserUtil { /** * 获取操作系统,浏览器及浏览器版本信息 * * @param request * @return */ public static String getOsAndBrowserInfo(HttpServletRequest request) { String browserDetails = request.getHeader("User-Agent"); String userAgent = browserDetails; String user = userAgent.toLowerCase(); String os = ""; String browser = ""; //=================OS Info======================= if (userAgent.toLowerCase().indexOf("windows") >= 0) { os = "Windows"; } else if (userAgent.toLowerCase().indexOf("mac") >= 0) { os = "Mac"; } else if (userAgent.toLowerCase().indexOf("x11") >= 0) { os = "Unix"; } else if (userAgent.toLowerCase().indexOf("android") >= 0) { os = "Android"; } else if (userAgent.toLowerCase().indexOf("iphone") >= 0) { os = "IPhone"; } else { os = "UnKnown, More-Info: " + userAgent; } //===============Browser=========================== if (user.contains("edge")) { browser = (userAgent.substring(userAgent.indexOf("Edge")).split(" ")[0]).replace("/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值