我的Java学习时间线:
height="2500" width="100%" src="http://yao2san.com/other/timeline/index.html" scrolling="no"><iframe>
第一阶段到此结束。
以下是这大半年以来所写的一些项目或者工具:
1.云打印
2.新闻与博客
3.文本情感评分
4.我们的博客
地址:完善中
**
5.HCI实验室
地址:完善中
6.java爬虫
地址:https://gitee.com/xgpxg/crawler
下面是对这差不多10个月的Java学习中遇到的问题的一个总结(以下总结是我暂且记得的印象比较深刻的一个总结)。
●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
- 一、 Java部分
Java基础
- 二、 web部分
html、js、jQuery、amaze
- 三、 数据库部分
mysql
- 四、 后端部分
struts、hibernate、spring、springmvc、tomcat
- 五、 其他
json、ansj、jsoup
一、 Java部分
1. 类的继承问题
对于类的继承一开始是不习惯的,而且是把好多个类写在一个大类里边,并没有体现出继承的思想。随着学习的深入,慢慢理解了继承的好处,进而把一些公共的、常用的方法单独提取到一个类里边,子类继承它就可以有它的方法和属性,很是方便,增加了代码的重用性。
这里对于Java中类的修饰符做一个回顾:
共有4个基本的权限修饰符。按访问权限从低到高依次为:private,protect,friendly和public
修饰符 | 范围 |
---|---|
private | 仅本类可见,不可继承 |
protect | 继承可见 |
friendly | 默认的,包内可见 |
public | 对于任何类都可见 |
2.接口问题
一开始是不喜欢用接口的,因为觉得接口里边什么都没写,就是定义了一些方法,而且还没有实现这些方法,意义不大。就像下面这样:
public interface IBlogDao {
/**
* 保存一篇博客
* @param blog
* @return
*/
public int save(BlogEntity blog);
/**
* 获取博客列表
* @param category
* 类别
* @param page
* 页数
* @param num
* 每页显示的条数
* @return
*/
public List<BlogEntity> getBlogList(String category,int page,int num);
/**
* 根据id获取博客
* @param bid
* 博客id
* @return
*/
public BlogEntity findById(int bid);
/**
* 获取博客数量
* @return
*/
public long getCount();
/**
* 根据关键字搜索
* @param kw
* 关键字
* @return
*/
public List<BlogEntity> search(String kw);
}
然而当写稍微复杂一点的项目时,发现接口是很有用的。它可以帮助我们梳理思路,理清一个大致的业务流程。这些接口就是一个个的模块,我们一点点的把这些模块写完之后,可以很顺利的组装在一起形成一个大的模块。
通过写个接口,在接口里边定义想要的功能,这样大大提高了开发效率。
二、web部分
1. 空格问题
在写登录程序的时候,查数据库发现明明查询出的数据和想要的数据和输入的数据一毛一样,但是就是不相等,很是无奈,最后在用鼠标乱点的时候发现查询出的数据好像最后有空格,因为能够选中而变成蓝色的,所以就想把尾部的空格给去掉,之后就没问题了。
这里边主要存在的问题是对数据库的字段数据类型不是很清楚导致的。
char、varchar的区别:
① char是定长的,例如char(10),不论存入的字符是多少(小于10),都会占用10个字符,如果不够10个,则用空格填充(大于10会被自动截取)。它的效率比较高,但是可能会浪费存储空间。所以一般用于存储手机号,身份证号,密码等字段。但是有人可能会问,密码为什么是定常的呢?因为密码一般不会以明文的 形式存入数据库,而是经过加密算法(如MD5、SHA等)加密后再入库,这些加密后的密码长度都是固定的(比如MD5有128位或者256位的),所以密码也比较适合用char来存储。
② varchar是不定长的,长度会更具实际数据的大小进行调整(当然要小于设定的最大长度,否则会被自动截取)。例如varchar(10),存入2个字符它的长度为3,因为还要用一位表示长度,所以总长度=实际字符长度+1。它适用于不确定长度的字段,比如用户名,商品名称等等。
所以在数据库中取出数据后,需要用trim()方法来去除首尾空格。(当然也可以用数据库中的trim()函数来去除空格)。而且在存一些表单数据的时候也最好吧首尾的空格去除掉。
2. 文件访问路径问题
在开始学习javaweb的时候,对于项目中文件的访问路径有些不解。不清楚要把文件放到哪个文件夹下。所以经常出现HTTP Status 404 – Not Found错误。经过一番摸索之后,发现文件应该这样放:
各个文件夹下的内容如下:
assets:静态资源文件,js、css、img等
doc:这个可以没有,我在这里编放了一些html文件
images:放图片
WEB-INF:这个里边的lib放项目用到的jar包,web.xml是web项目的配置文件,整个项目启动的时候最先用到的就是它。
WebContent下边就放一些常见的网页文件html,jsp等。(当然也可以放在web-inf下,但是这样好像是不能直接访问的,需要通过controller才能访问。或者在web.xml文件中配置访问路径也可以。)
3. 经常出现的404错误
在学习过程中经常出现404找不到的错误。这主要有两种情况:
一种是配置文件出错了,导致无法访问想要访问的资源。比如web.xml文件中存在错误,就会一直出现404错误。
还有一种是请求的url路径有误。也就是前端请求的action和后台的action名称不一样,导致无法映射该请求而出现404.
所以在写的时候真的需要很细心的呢。
4. jquery中选择器的问题
使用jquery进行操作元素的时候常常无法选取想要的元素,因为有些元素是动态生成的,不能直接选取,需要用jquery.on(“”,function(){})的形式选择,当时被这个问题困扰了好久。
5. ajax中的同步以及跨域问题
同步/异步问题:
在用ajax请求数据后想return请求到的数据,于是乎就在success回调函数中返回,结果自然是取不到值的,因为不会返回到外部的函数中。
所以就定义一个全局变量,在success中对这个全局变量赋值。但是还是无法取到值。为什么呢,被这个问题困扰了好久,最后才发现是应为异步的原因。因为请求数据需要一定的时间,在这个时间之前,其他代码已经被执行了(因为是异步的),所以获取不到值。最后的做法是将异步改为同步即可。(async=false)
跨域问题:
在请求的url中这样写:url="http://www.aa.com/xx.do"
这样会产生跨域问题,阻止跨域是浏览器的一种安全策略。但是我们可以通过jsonp来解决这个问题(要在服务器端定义好jsonp对象,它和json对象是不一样的,jsonp前边还包括回调函数的名称,并且在ajax中指定回调函数)。
跨域问题的服务器端还可以通过springmvc的@CrossOrigin(origins = "*")
的注解来解决(origins为跨域来源)
三、数据库部分
1. mysql的连接数问题
在采集网页数据的时候,需要将数据保存到数据库,在程序运行一段时间后发现并没有新数据插入,而报连接太多错误。
Too many connections
一开始对于这种错误只是将数据库重新启动,再继续运行,但是这样很麻烦,所以就找了另外两种解决方法。
修改最大连接数
set GLOBAL max_connections=500;
这样通过增加了最大连接数来保证更多的连接可以继续进行。但是时间一长,这样还是会报错。所以又采用第二种方法。
修改连接超时时间
//show global variables like 'wait_timeout' set global wait_timeout=300; //show global variables like 'interactive_timeout'; set global interactive_timeout=300;
mysql默认的连接超时时间是8小时,这里改成300秒,即5分钟,就不会出现连接太多的问题了。可以用status
命令来查看当前连接的线程数。
2. 手动更新Mysql报错
当用sql更新数据库的时候报错:
Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column To disable safe mode, toggle the option in Preferences -> SQL Queries and reconnect.
因为MySQL默认的是开启了安全模式的,不能手动更新数据,所以需要关闭该模式:
SET SQL_SAFE_UPDATES = 0
在更新完之后可以再修改为安全模式即可
SET SQL_SAFE_UPDATES = 1
四、后端部分
1. struts
最先接触到的框架就是struts,因为它代替了servlet干的事情,将请求映射到不同的类上。它的MVC模式也对开发带来了极大的方便。
然而一堆配置文件是很容易出错的事情。并且它是将请求和类的映射写在xml文件中的,虽然这样很方便维护,但是我觉得在开发的过程中很是不变,因为要切换界面,不太喜欢。
对于struts的配置文件再回顾一下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<package name="login" namespace="" extends="struts-default">
<action name="login" class="login.LoginAction" method="execute">
<result name="success" type="redirectAction">index</result>
<result name="input">/login.jsp</result>
</action>
<action name="regist" class="login.RegistAction" method="execute">
<result name="success">/login.jsp</result>
<result name="input">/login.jsp</result>
</action>
</package>
<package name="pageAction" namespace="" extends="struts-default">
<interceptors>
<!-- 拦截器 -->
<interceptor name="loginCheck" class="interceptor.LoginCheck" />
<!-- 拦截器栈 -->
<interceptor-stack name="myStack">
<interceptor-ref name="loginCheck"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref><!-- 默认的 -->
</interceptor-stack>
</interceptors>
<!-- 设置为默认的拦截器 ,会自动应用到每包内每一个的action -->
<default-interceptor-ref name="myStack" />
<!-- 定义全局Result -->
<global-results>
<!-- 当返回login视图名时,转入/login.jsp页面 -->
<result name="needLogin">/login.jsp</result>
</global-results>
<action name="index" class="pageAction.IndexAction" method="execute">
<result name="success">/index.jsp</result>
<result name="error">/test/error.jsp</result>
</action>
<action name="fileupload" class="pageAction.FileUploadAction"
method="execute">
<result name="success">/home.jsp</result>
</action>
<action name="order" class="pageAction.OrderAction" method="execute">
<result name="success" type="redirectAction">pay</result>
</action>
<action name="msg" class="pageAction.UserMsg" method="execute">
<result name="success" type="redirectAction">pay</result>
</action>
<action name="cleanOrderMsg" class="pageAction.UserMsg" method="cleanOrderMsg">
<result name="success" type="redirectAction">x</result>
</action>
<!-- 文件下载 -->
<action name="fileDownload" class="pageAction.PrintAction">
<result name="success" type="stream">
<param name="contentType">application/octet-stream</param><!-- 指定下载文件类型 -->
<param name="contentDisposition">attachment;filename="${fileName}"</param><!-- filename="${fileName}"指定下载文件名 -->
<param name="inputName">downloadFile</param>
<param name="bufferSize">1024</param><!--指定下载文件缓存的大小 -->
</result>
</action>
<action name="printing" class="pageAction.PrintingAction" method="execute">
<result name="success">x</result>
</action>
<action name="getPrice" class="pageAction.GetPriceAction" method="execute">
<result name="success">x</result>
</action>
<action name="order_picture" class="pageAction.OrderAction" method="execute">
<result name="success" type="redirectAction">pay</result>
<result name="input">/picturePrint.jsp</result>
</action>
<action name="userInfo" class="pageAction.UserInfoAction" method="execute">
<result name="input">/myhome.jsp</result>
</action>
<action name="recharge" class="pageAction.RechargeAction" method="execute">
<result name="input">/myhome.jsp</result>
</action>
</package>
</struts>
< package >标签指定哪些包为action,namespace指定了包的访问路径,extends=”struts-default”表示继承struts
这里边最主要的就是< action >标签,它里边有这么几个属性:
name:action的名称,也就是请求的url地址
class:要映射的类
method:要映射的方法
result:要返回的视图结果。其中name为返回类型,可以是success,error,input(用于验证失败返回到输入页面)等等
对于struts已经有段时间没用了,就记得这么多了。
2.spring
这是个很好的框架,尤其是它的依赖注入和面向切面的思想。
依赖注入:将对象放到spring的Factory中,不用自己在new对象,需要使用的时候只需要用注解的方式注入对象即可。这样从头到尾就只用到了一个对象,节省了大量的内存空间,也提高了性能。
切面编程:在不修改原有代码的情况下,对原有代码进行一定的操作。常用于日志处理等方面。
对于spring目前主要用到了它的依赖注入以及日志处理的时候的面向切面的方法。
在依赖注入中用的最多的就是@Autowired注解,它是根据类型自动注入的,并且注入对象不可以为null,否则报错,如果允许为空则可以设置它的required属性为false。而@Resource和@Autowwired类似,只不过它注入的对象可以为空。@Autowired是默认按照类型进行装配的,而@Resource是按照name进行装配的,在找不到相同的name时才按照类型进行装配。他们都可以写在字段或者setter方法上。
切面编程目前只是用于日志处理的方面。定义一个切面和切点:(借用别人的一个例子)
@Aspect
public class Audience {
@Pointcut("execution(* com.springinaction.aop.Performer.perform(..))")
public void performance() {} // 定义切点
@Before("performance()")
public void takeSeats() {
// 节目开始之前
System.out.println("演出前——观众开始入座");
}
@Before("performance()")
public void turnOffCellPhones() {
// 节目开始之前
System.out.println("演出前——观众关机或静音");
}
@AfterReturning("performance()")
public void applaud() {
// 节目成功结束之后
System.out.println("演出很成功——观众鼓掌:啪啪啪");
}
@AfterThrowing("performance()")
public void demandRefund() {
// 节目表演失败之后
System.out.println("节目演出很失败——切!一点都不好看,我们要求退钱!");
}
}
有了这样的切面编程,就可以不用在原文件里添加代码了。可以很方便的对原来的代码进行日志输出。
3. hibernate
这是一个数据库的框架,它是基于jdbc的,对jdbc进行了封装,使得对数据库的操作变得简单。
在刚开始的时候并没有用到它的sessionFactory,只是简单的用到了它的save、update等方法。对数据持久化也不是很理解。而且每次都是手动开启或关闭事物,手动释放连接。这样很容易出错。
最初觉得实体映射用注解并没有xml文件好用,但是当字段多了以后在配置文件里写就比较麻烦了,所以就采用了注解的形式,方便很多(当然也可以用逆向工程来生成实体类)
这是一个hibernate的xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 数据源和事物的配置 -->
<context:property-placeholder location="classpath:application.properties" />
<!-- sessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.yao2san.entity,com.yao2san.controller,com.yao2san.util" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<!-- <prop key="hibernate.current_session_context_class">thread</prop> -->
</props>
</property>
</bean>
<!-- dataSource -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!-- these are C3P0 properties -->
<property name="acquireIncrement" value="${c3p0.acquireIncrement}" />
<property name="minPoolSize" value="${c3p0.minPoolSize}" />
<property name="maxPoolSize" value="${c3p0.maxPoolSize}" />
<property name="maxIdleTime" value="${c3p0.maxIdleTime}" />
</bean>
<!-- 配置Hibernate事务管理器 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 事物注解配置 -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- <property name="prefix" value="/"/> <property name="suffix" value=".jsp"/> -->
</bean>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
<!-- <import resource="classpath:beans.xml"/> -->
</beans>
数据库的配置:
#hibernate
hibernate.max_fetch_depth=3
hibernate.jdbc.fetch_size=50
hibernate.jdbc.batch_size=10
hibernate.show_sql=true
hibernate.cache.use_second_level_cache=true
hibernate.cache.use_query_cache=true
hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
#jdbc
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/blog?useSSL=true
jdbc.username=root
jdbc.password=1571
jdbc.maxActive=50
#c3p0
c3p0.acquireIncrement=10
c3p0.minPoolSize=3
c3p0.maxPoolSize=200
c3p0.maxIdleTime=6000
其中hibernate的事物管理器也很好用,这样就不用我们手动关闭连接,也不用手动提交事物了。
4. springmvc
springmvc和struts类似,都是mvc模式。但是springmvc对请求的处理是方法级别的,而struts是类级别的,所以springmvc更灵活。而且个人觉得springmvc中的注解很好用,很方便,也很好理解。
5. 编码问题
编码不统一,经常出现各种乱码,很是痛苦。所以从建立项目开始就统一编码为utf8。包括Java文件,页面文件,配置文件等各种文件都修改为utf8(eclipse可以直接修改项目文件编码,其中的文件会自动继承该编码)
为了解决springMvc中的乱码问题,可以在web.xml文件中加这么一段话:
<!-- 统一编码 解决中文乱码问题-->
<filter>
<filter-name>charsetEncoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>charsetEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
这样请求或响应的数据就不是乱码了。
五、其他
1.nlp
nlp就是文本处理的意思,主要看了ansj的中文分词框架,只是有一个简单的认识,以及会使用一些简单的分词以及词频和关键字的提取。
2.jsoup
这是一个网页数据获取和分析的框架,用它做了几个Java的小爬虫,爬取了一些网页进行了词频同意、关键字提取等分析。
结语
虽然ssh框架已经了解了大概,也能利用ssh完成项目的开发,但是对其深层次的原理也还不是很清楚,所以,在下个阶段更要好好的去深入理解这些框架的原理,同时学习新的框架spring boot来提高开发效率。当然对于基础的知识例如数据结构等还需要加强巩固
2017年马上就要结束了,这一年不仅仅是收获到了知识,也收了一位可爱的小朋友。在即将到来的2018年里,希望我们都越来越好,希望我最亲爱可爱的小朋友考研顺利呀。( •̀ ω •́ )y