230 likes | 383 Views
Lab Exercise 02. Quiz App: MVC Pattern and Data Access. Mikus Visendorfs Voldemārs Hercovs-Hercbergs Agnese Zalcmane. Uzdevums. Pirmā uzdevuma ietvaros izveidota funkcionalitāte sekojošiem moduļiem Testa sagatavju saraksts, labošana, dzēšana Moduļu saraksts, labošana, dzēšana
E N D
Lab Exercise 02. Quiz App: MVC Pattern and Data Access Mikus Visendorfs Voldemārs Hercovs-Hercbergs Agnese Zalcmane
Uzdevums Pirmā uzdevuma ietvaros izveidota funkcionalitāte sekojošiem moduļiem • Testa sagatavju saraksts, labošana, dzēšana • Moduļu saraksts, labošana, dzēšana • Jautājumu saraksts, labošana, dzēšana • Atbilžu variantu saraksts, labošana, dzēšana • Testu pildīšana, atbilžu atzīmēšana, novērtēšana, saglabāšana un atrādīšana
2. Uzdevums • LasiitXml.java: • Atbilstoši prasībām ir izveidots .java fails ar main metodi xml failu pievienošanai datu bāzei. • XML faila nosaukums ir jāpadod programmai kā parametrs • XML'a nolasīšanai tiek izmantots SAX - kas xml interpretē kā notikumu plūsmu, izdalot notikumus: • - xml dokumenta sākums/beigas • - xml elementa sākums/beigas • - xml elementa saturs • Datu ierakstīšanai datu bāzē tiek izmantots JDBC draiveris.
3. Uzdevums • Izveidots Hibernate mapping objekta Image blob objektam • Izveidoti augšup un lejuplādes kontrolieri • Izveidots un piedefinēts spring skatījums attēlu u.c. augšuielādēto failu skatīšanai
4. Uzdevums • Visur, kur nepieciešama dalīšana pa lapām jāpieraksta: • <c:if test="${previousPage != -10}"><a href="listall?offset=${previousPage}"/>Iepriekšējā lapa </a></c:if> • <c:if test="${nextPage>0}"><a href="listall?offset=${nextPage}"/>Nākamā lapa</a></c:if> • Savukārt ListAllController.java jāizmaina uz šo: public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { ModelAndView result = new ModelAndView(viewName); String firstRes= request.getParameter("offset"); int firstResult=0; int nextPage=0; if (firstRes!=null&&!firstRes.equals("")) firstResult=Integer.parseInt(firstRes); List list = dao.getAll(firstResult,21); if (list.size()==21){ list.remove(20); nextPage=firstResult+20; } if (firstResult==0) result.addObject("previousPage",-10); else result.addObject("previousPage",firstResult-20); result.addObject("nextPage",nextPage); result.addObject("list",list); return result; }
4. Uzdevums • Lapai tiek padoti mainīgie - nextPage un previousPage, lapā atbilstoši padotajām vērtībām tiek rādīts/nerādīts 'Nākamā lapa' un 'Iepriekšējā lapa'. No lapas tiek atgriezts mainīgais offset - nobīde skaitot no pirmā datu bāzes elementa. • Lai viss iepriekš minētais strādātu CommonDao.java tika papildināta ar šo funkciju: public List getAll(int offset, int length) { String query = getAllQueries.get(clazz); if (query == null) { query = "from " + clazz.getName(); } Session session = getSession(); Query q = session.createQuery(query); if (length > 0) { q.setFirstResult(offset); q.setMaxResults(length); } List list = q.list(); releaseSession(session); return list; } • kurā atšķirībā no orģinālās getAll() ir parametri offset un length, ar kuru palīdzību tiek ierobežots iegūtais rezultāts formā - offset - nobīde no pirmā elementa, length - elementu skaits.
5. Uzdevums • Personu un jautājumu tipu moduļos lietotājam, kas nav 'admin', kontrolierī tiek izlaista darbība, spiežot pogas 'Pievienot' un 'Dzēst' • Ne-’admin’ lietotāji, spiežot linku 'Edit‘ personu un jautājumu tipu moduļos tiek redirektēti uz welcome lapu • Saglabājot personu, ne-’admin’ lietotājam tas tiek atļauts tikai tad, ja viņš vēl nav pieslēdzies un vēlas reģistrēties. Citu lietotāju datus labot nav atļauts • Pieejami divi testa sagatavju saraksti – ‘Manas sagataves’, kur tiek attēlotas tikai lietotāja izveidotās sagataves un ‘Visas sagataves’, kur tiek attēlotas visas sagataves, bet labot tiek ļauts tikai lietotāja izveidotās sagataves. • Navigācija pa dažādiem moduļiem atļauta tikai piereģistrētiem lietotājiem, pirms tam izvēlnē tiek rādītas tikai sadaļas ‘Sākums’ un ‘Pieslēgties’.
6. Uzdevums • Izveidots konekciju pool: <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost/portaledu?autoReconnect=false&useUnicode=true&characterEncoding=utf8"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean>
6. Uzdevums • Izveidots ServletContextListener, kurš klausās uz konteksta undeploy un iztīra beanu kešu, uz kuru paliek reference no classloader, kur pie deploy netiek izmests ārā: publicclass CleanupListener implements ServletContextListener { publicvoid contextDestroyed(ServletContextEvent event) { try { Introspector.flushCaches(); System.gc(); } catch (Throwable e) { System.err.println("... failled to cleanup ClassLoader "); e.printStackTrace(); } } }
6. uzdevums • Izmantojot Tomcat (un līdz ar to arī JBoss), pie konteksta undeploy, noteiktu iemeslu dēļ nevar tikt atbrīvots classloader, kurš patur references uz bīniem. Nav zināms, kādēļ šī problēma rodas, bet ir zināms apejas ceļš – izmantojot BEA JRockit(R) JDK. Šādā gadījumā bīni tiek atbrīvoti un OutOfMemoryError šādā veidā nevar atkārtot
Selenium testi • Lai izietu selenium testu kopu, tie bija jālabo saistībā ar 5. uzdevuma prasībām u.c. drošības lietām, piemēram, lietotāju moduļa testos jāpieliek ielogošanās, jo lietotājam nav pieejams šāds izvēlnes posms, ja viņš nav admin lietotājs • Interesanta iezīme – testi neiziet, ja tos darbina ātrajā režīmā.
JUnit testi Ar JUnit testiem ir saistītas vairākas problēmas: • Pēc Hibernate ideoloģijas, objekti ir jāsalīdzina izmantojot datubāzes ekvivalenci – t.i. objekti ir ekvivalenti tad un tikai tad, ja ekvivalenti ir to identifikatori. Pretējā gadījumā Hibernate var neveikt paredzētās darbības (piemēram, ievietot jaunu objektu labošanas vietā utt.). JUnit testi turpretī izmanto to, ka objektu equals metode salīdzina lauku vērtības (izņemot id).
JUnit testi • Lai notestētu, piemēram, objekta Variant uzvedību, to saglabājot, nepieciešams saglabāt arī visus obligātos tā vecākus – Question, Module, Person. Līdz ar to testu @Before metodes kļūst pat lielākas par pašiem testiem, kas mācību uzdevumā nav saprātīgs apjoms. • Pēc vispārējās ideoloģijas, testi ir jāraksta pirms koda, vadoties no specifikācijas. Šajā gadījumā par specifikāciju varētu uzskatīt jau gatavos testus un Hibernate mappingu. Tomēr 1.uzdevuma risināšanas gaitā tapa skaidrs, ka daudzas jau it kā gatavās lietas tomēr neatbilst paraugā dotajai ruby aplikāciju un ir jāpārtaisa un tas diezgan daudz atsaucas uz testiem. Tādēļ netika rakstīti, papildināti un izlaboti visi testi, bet ilustrācijas dēļ tikai lv.webkursi.mtest.lab02.dao.ModuleDaoTest un lv.webkursi.mtest.lab02.dao.AbstractDaoTest
JUnit testi • Izmaiņas primāri skar setUp() metodi, kas, lai būtu iespējams notestēt moduļus, izveido saistīto Person klasi un to saglabā: private Long personId; public Person createTestPerson() { Person p2 = new Person(); p2.setEmail("email"); p2.setFirstName("firstname"); p2.setLastName("lastname"); p2.setLogin("login"); p2.setPassword("password2"); CommonDao personDao = DaoUtils.getDao(Person.class); personDao.saveOrUpdate(p2); return p2; } @Before publicvoid setUp() { dao.setSessionFactory(DaoUtils.getSessionFactory()); PersonId = createTestPerson().getId(); }
JUnit testi • Izveidoto personId izmanto getDynamicObjectX() metodes, veidojot testa datus: public Object getDynamicObjectA() { Module mA = new Module(); mA.setName("MA"); mA.setTitle("MA_Title"); mA.setDescription("MA_Description"); mA.setAuthorId(personId); return mA; }
JUnit testi • Testējot moduļus ar jautājumiem, setUp daļa jau kļūst lielāka: private QuestionType qt = (QuestionType) (new QuestionTypeDaoTest.CommonDaoTest() .getDynamicObjectA()); private Module m;// = (Module) (new ModuleDaoTest.CommonDaoTest().getDynamicObjectA()); @Before publicvoid setUp() throws Exception { m = (Module) (new ModuleDaoTest.CommonDaoTest().getDynamicObjectA()); Person person = new Person(); person.setEmail("email."); person.setFirstName("firstname."); person.setLastName("lastname."); person.setLogin("login."); person.setPassword("password2."); dao.setSessionFactory(DaoUtils.getSessionFactory()); dao.saveOrUpdate(person); m.setAuthorId(person.getId()); dao.saveOrUpdate(m); dao.saveOrUpdate(qt); }
JUnit testi • Jāpārraksta ir arī lv.webkursi.mtest.lab02.dao.AbstractDaoTest metodes, kas salīdzina datus, piemēram: @Test publicvoid listOrdering() { commonDao.saveOrUpdate(getDynamicObjectC()); commonDao.saveOrUpdate(getDynamicObjectA()); commonDao.saveOrUpdate(getDynamicObjectB()); List<ContentItem> result = commonDao.getAll(); assertEquals(3,result.size()); assertEquals(((ContentItem)getDynamicObjectA()).getDescription(),result.get(0).getDescription()); assertEquals(((ContentItem)getDynamicObjectB()).getDescription(),result.get(1).getDescription()); assertEquals(((ContentItem)getDynamicObjectC()).getDescription(),result.get(2).getDescription()); }